DSPWrapper.hpp
1 #pragma once
2 #include <Process/Dataflow/PortFactory.hpp>
3 #include <Process/Execution/ProcessComponent.hpp>
4 #include <Process/ExecutionContext.hpp>
5 #include <Process/GenericProcessFactory.hpp>
6 #include <Process/Process.hpp>
7 #include <Process/ProcessFactory.hpp>
8 
9 #include <Control/DefaultEffectItem.hpp>
10 #include <Effect/EffectFactory.hpp>
11 
12 #include <score/tools/IdentifierGeneration.hpp>
13 
14 #include <ossia/dataflow/execution_state.hpp>
15 #include <ossia/dataflow/node_process.hpp>
16 
17 #include <Faust/FaustUtils.hpp>
18 
19 namespace FaustDSP
20 {
21 template <typename DSP>
22 class Fx;
23 }
24 
25 template <typename DSP>
26 struct Metadata<Category_k, FaustDSP::Fx<DSP>>
27 {
28  static Q_DECL_RELAXED_CONSTEXPR const char* get() { return "Audio"; }
29 };
30 template <typename DSP>
31 struct Metadata<Tags_k, FaustDSP::Fx<DSP>>
32 {
33  static QStringList get()
34  {
35  QStringList lst{"Audio"};
36  return lst;
37  }
38 };
39 template <typename DSP>
41 {
42  static Process::ProcessFlags get() { return Process::ProcessFlags::SupportsAll; }
43 };
44 template <typename DSP>
45 struct Metadata<Process::Descriptor_k, FaustDSP::Fx<DSP>>
46 {
47  static std::vector<Process::PortType> inletDescription()
48  {
49  std::vector<Process::PortType> port;
50  port.push_back(Process::PortType::Audio);
51  return port;
52  }
53  static std::vector<Process::PortType> outletDescription()
54  {
55  std::vector<Process::PortType> port;
56  port.push_back(Process::PortType::Audio);
57  return port;
58  }
59  static Process::Descriptor get()
60  {
61  static Process::Descriptor desc{
63  Process::ProcessCategory::AudioEffect,
65  "Faust effect",
66  "Faust",
68  inletDescription(),
69  outletDescription()};
70  return desc;
71  }
72 };
73 
74 namespace FaustDSP
75 {
76 template <typename T>
77 struct Wrap final : UI
78 {
79  template <typename... Args>
80  Wrap(Args&&... args)
81  : t{args...}
82  {
83  }
84 
85  T t;
86  void openTabBox(const char* label) override { t.openTabBox(label); }
87  void openHorizontalBox(const char* label) override { t.openHorizontalBox(label); }
88  void openVerticalBox(const char* label) override { t.openVerticalBox(label); }
89  void closeBox() override { t.closeBox(); }
90  void declare(FAUSTFLOAT* zone, const char* key, const char* val) override
91  {
92  t.declare(zone, key, val);
93  }
94  void
95  addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) override
96  {
97  t.addSoundfile(label, filename, sf_zone);
98  }
99  void addButton(const char* label, FAUSTFLOAT* zone) override
100  {
101  t.addButton(label, zone);
102  }
103  void addCheckButton(const char* label, FAUSTFLOAT* zone) override
104  {
105  t.addCheckButton(label, zone);
106  }
107  void addVerticalSlider(
108  const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
109  FAUSTFLOAT max, FAUSTFLOAT step) override
110  {
111  t.addVerticalSlider(label, zone, init, min, max, step);
112  }
113  void addHorizontalSlider(
114  const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
115  FAUSTFLOAT max, FAUSTFLOAT step) override
116  {
117  t.addHorizontalSlider(label, zone, init, min, max, step);
118  }
119  void addNumEntry(
120  const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
121  FAUSTFLOAT max, FAUSTFLOAT step) override
122  {
123  t.addNumEntry(label, zone, init, min, max, step);
124  }
125  void addHorizontalBargraph(
126  const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) override
127  {
128  t.addHorizontalBargraph(label, zone, min, max);
129  }
130  void addVerticalBargraph(
131  const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) override
132  {
133  t.addVerticalBargraph(label, zone, min, max);
134  }
135 };
136 
137 template <typename DSP>
138 class Fx final : public Process::ProcessModel
139 {
140  SCORE_SERIALIZE_FRIENDS
141  PROCESS_METADATA_IMPL(Fx)
142 
143 public:
144  Fx(TimeVal t, const Id<Process::ProcessModel>& id, QObject* parent)
146  {
147  Wrap<Faust::UI<decltype(*this)>> ui{*this};
148  DSP d;
149 
150  m_inlets.push_back(new Process::Inlet{getStrongId(m_inlets), this});
151  m_inlets.back()->type = Process::PortType::Audio;
152  m_outlets.push_back(new Process::Outlet{getStrongId(m_outlets), this});
153  m_outlets.back()->type = Process::PortType::Audio;
154  m_outlets.back()->setPropagate(true);
155 
156  d.buildUserInterface(&ui);
157  }
158 
159  ~Fx() override { }
160 
161  template <typename Impl>
162  Fx(Impl& vis, QObject* parent)
163  : Process::ProcessModel{vis, parent}
164  {
165  vis.writeTo(*this);
166  }
167 
168  QString prettyName() const noexcept override
169  {
171  }
172 
173  Process::Inlets& inlets() { return m_inlets; }
174  Process::Outlets& outlets() { return m_outlets; }
175  const Process::Inlets& inlets() const { return m_inlets; }
176  const Process::Outlets& outlets() const { return m_outlets; }
177 
178  bool hasExternalUI() const noexcept { return false; }
179 };
180 
181 template <typename DSP>
182 class Executor final : public Execution::ProcessComponent_T<Fx<DSP>, ossia::node_process>
183 {
184 
185 public:
186  static constexpr bool is_unique = true;
187 
188  class exec_node final : public ossia::graph_node
189  {
190  public:
191  DSP dsp;
192  ossia::small_vector<std::pair<ossia::value_port*, FAUSTFLOAT*>, 8> controls;
193  exec_node()
194  {
195  m_inlets.push_back(new ossia::audio_inlet);
196  m_outlets.push_back(new ossia::audio_outlet);
198  dsp.buildUserInterface(&ex);
199  }
200 
201  void run(const ossia::token_request& tk, ossia::exec_state_facade) noexcept override
202  {
203  ossia::nodes::faust_exec(*this, dsp, tk);
204  }
205 
206  std::string label() const noexcept override { return "Faust"; }
207 
208  void all_notes_off() noexcept override { }
209  };
210 
211  static Q_DECL_RELAXED_CONSTEXPR score::Component::Key static_key() noexcept
212  {
213  return Metadata<ConcreteKey_k, Fx<DSP>>::get().impl();
214  }
215 
216  score::Component::Key key() const noexcept final override { return static_key(); }
217 
218  bool key_match(score::Component::Key other) const noexcept final override
219  {
220  return static_key() == other || Execution::ProcessComponent::base_key_match(other);
221  }
222 
223  Executor(Fx<DSP>& proc, const Execution::Context& ctx, QObject* parent)
224  : Execution::ProcessComponent_T<Fx<DSP>, ossia::node_process>{
225  proc, ctx, "FaustComponent", parent}
226  {
227  auto node = ossia::make_node<exec_node>(*ctx.execState);
228  this->node = node;
229  this->m_ossia_process = std::make_shared<ossia::node_process>(node);
230  node->dsp.instanceInit(ctx.execState->sampleRate);
231 
232  for(std::size_t i = 1; i < proc.inlets().size(); i++)
233  {
234  auto inlet = static_cast<Process::ControlInlet*>(proc.inlets()[i]);
235  *node->controls[i - 1].second = ossia::convert<double>(inlet->value());
236  auto inl = this->node->inputs()[i];
237  QObject::connect(
238  inlet, &Process::ControlInlet::valueChanged, this,
239  [this, inl](const ossia::value& v) {
240  this->system().executionQueue.enqueue([inl, val = v]() mutable {
241  inl->data.template target<ossia::value_port>()->write_value(std::move(val), 0);
242  });
243  });
244  }
245  }
246 };
247 }
248 
249 template <typename DSP>
250 struct is_custom_serialized<FaustDSP::Fx<DSP>> : std::true_type
251 {
252 };
253 
254 template <typename DSP>
255 struct TSerializer<DataStream, FaustDSP::Fx<DSP>>
256 {
258  static void readFrom(DataStream::Serializer& s, const model_type& eff)
259  {
260  readPorts(s, eff.inlets(), eff.outlets());
261  s.insertDelimiter();
262  }
263 
264  static void writeTo(DataStream::Deserializer& s, model_type& eff)
265  {
266  writePorts(
267  s, s.components.interfaces<Process::PortFactoryList>(), eff.inlets(),
268  eff.outlets(), &eff);
269 
270  s.checkDelimiter();
271  }
272 };
273 
274 template <typename DSP>
275 struct TSerializer<JSONObject, FaustDSP::Fx<DSP>>
276 {
278  static void readFrom(JSONObject::Serializer& s, const model_type& eff)
279  {
280  readPorts(s.obj, eff.inlets(), eff.outlets());
281  }
282 
283  static void writeTo(JSONObject::Deserializer& s, model_type& eff)
284  {
285  writePorts(
286  s.obj, s.components.interfaces<Process::PortFactoryList>(), eff.inlets(),
287  eff.outlets(), &eff);
288  }
289 };
290 
291 namespace FaustDSP
292 {
293 template <typename DSP>
294 using ProcessFactory = Process::ProcessFactory_T<Fx<DSP>>;
295 
296 template <typename DSP>
298 
299 template <typename DSP>
301 }
Metadata to categorize objects: curves, audio, etc.
Definition: lib/score/tools/Metadata.hpp:61
Definition: VisitorInterface.hpp:53
Definition: DataStreamVisitor.hpp:27
Definition: DataStreamVisitor.hpp:202
Definition: Process/Execution/ProcessComponent.hpp:119
Definition: DSPWrapper.hpp:189
Definition: DSPWrapper.hpp:183
Definition: DSPWrapper.hpp:139
Definition: VisitorInterface.hpp:61
Definition: JSONVisitor.hpp:52
Definition: JSONVisitor.hpp:423
Definition: Port.hpp:203
Definition: DefaultEffectItem.hpp:26
Definition: EffectFactory.hpp:66
Definition: Port.hpp:177
Definition: Port.hpp:273
Definition: PortFactory.hpp:74
Definition: GenericProcessFactory.hpp:15
The Process class.
Definition: score-lib-process/Process/Process.hpp:61
Metadata to retrieve the ProcessFlags of a process.
Metadata to associate tags to objects.
Definition: lib/score/tools/Metadata.hpp:67
The id_base_t class.
Definition: Identifier.hpp:57
Components used for the execution of a score.
Definition: ProcessComponent.cpp:12
Base classes and tools to implement processes and layers.
Definition: JSONVisitor.hpp:1324
ProcessFlags
Various settings for processes.
Definition: ProcessFlags.hpp:17
Definition: ExecutionContext.hpp:76
Definition: Process/Execution/ProcessComponent.hpp:89
Definition: score-plugin-faust/Faust/Utils.hpp:23
Definition: DSPWrapper.hpp:78
Static metadata implementation.
Definition: lib/score/tools/Metadata.hpp:36
Definition: score-lib-process/Process/ProcessMetadata.hpp:37
Definition: PortForward.hpp:23
Definition: PortForward.hpp:27
Definition: VisitorInterface.hpp:13
Definition: TimeValue.hpp:21