score-plugin-engine/Engine/Node/Process.hpp
1 #pragma once
2 #include <Process/Dataflow/Port.hpp>
3 #include <Process/Dataflow/PortFactory.hpp>
4 #include <Process/Process.hpp>
5 #include <Process/ProcessFactory.hpp>
6 #include <Process/ProcessMetadata.hpp>
7 
8 #include <score/application/ApplicationComponents.hpp>
9 #include <score/model/EntityMapSerialization.hpp>
10 #include <score/plugins/DeserializeKnownSubType.hpp>
11 #include <score/plugins/SerializableHelpers.hpp>
12 
13 #include <ossia/dataflow/safe_nodes/node.hpp>
14 #include <ossia/detail/algorithms.hpp>
15 #include <ossia/detail/for_each.hpp>
16 #include <ossia/detail/for_each_in_tuple.hpp>
17 
19 namespace Control
20 {
21 struct is_control
22 {
23 };
24 template <typename Info, typename = is_control>
25 class ControlProcess;
26 }
27 template <typename Info>
28 struct Metadata<PrettyName_k, Control::ControlProcess<Info>>
29 {
30  static Q_DECL_RELAXED_CONSTEXPR auto get() { return Info::Metadata::prettyName; }
31 };
32 template <typename Info>
33 struct Metadata<Category_k, Control::ControlProcess<Info>>
34 {
35  static Q_DECL_RELAXED_CONSTEXPR auto get() { return Info::Metadata::category; }
36 };
37 template <typename Info>
38 struct Metadata<Tags_k, Control::ControlProcess<Info>>
39 {
40  static QStringList get()
41  {
42  QStringList lst;
43  for(auto str : Info::Metadata::tags)
44  lst.append(str);
45  return lst;
46  }
47 };
48 
49 template <typename Info>
50 struct Metadata<Process::Descriptor_k, Control::ControlProcess<Info>>
51 {
52  static std::vector<Process::PortType> inletDescription()
53  {
54  std::vector<Process::PortType> port;
55  for(std::size_t i = 0; i < std::size(Info::Metadata::audio_ins); i++)
56  {
57  port.push_back(Process::PortType::Audio);
58  }
59  for(std::size_t i = 0; i < std::size(Info::Metadata::midi_ins); i++)
60  {
61  port.push_back(Process::PortType::Midi);
62  }
63  for(std::size_t i = 0; i < std::size(Info::Metadata::value_ins); i++)
64  {
65  port.push_back(Process::PortType::Message);
66  }
67  for(std::size_t i = 0; i < std::size(Info::Metadata::address_ins); i++)
68  {
69  port.push_back(Process::PortType::Message);
70  }
71  for(std::size_t i = 0; i < std::tuple_size_v<decltype(Info::Metadata::controls)>;
72  i++)
73  port.push_back(Process::PortType::Message);
74  return port;
75  }
76  static std::vector<Process::PortType> outletDescription()
77  {
78  std::vector<Process::PortType> port;
79  for(std::size_t i = 0; i < std::size(Info::Metadata::audio_outs); i++)
80  {
81  port.push_back(Process::PortType::Audio);
82  }
83  for(std::size_t i = 0; i < std::size(Info::Metadata::midi_outs); i++)
84  {
85  port.push_back(Process::PortType::Midi);
86  }
87  for(std::size_t i = 0; i < std::size(Info::Metadata::value_outs); i++)
88  {
89  port.push_back(Process::PortType::Message);
90  }
91  return port;
92  }
93  static Process::Descriptor get()
94  {
95  static Process::Descriptor desc{
96  Info::Metadata::prettyName,
97  (Process::ProcessCategory)Info::Metadata::kind,
98  Info::Metadata::category,
99  Info::Metadata::description,
100  Info::Metadata::author,
102  inletDescription(),
103  outletDescription()};
104  return desc;
105  }
106 };
107 template <typename Info>
109 {
110  static Process::ProcessFlags get() noexcept
111  {
112  return (Process::ProcessFlags)Info::Metadata::flags;
113  }
114 };
115 template <typename Info>
116 struct Metadata<ObjectKey_k, Control::ControlProcess<Info>>
117 {
118  static Q_DECL_RELAXED_CONSTEXPR auto get() noexcept
119  {
120  return Info::Metadata::objectKey;
121  }
122 };
123 template <typename Info>
124 struct Metadata<ConcreteKey_k, Control::ControlProcess<Info>>
125 {
126  static Q_DECL_RELAXED_CONSTEXPR UuidKey<Process::ProcessModel> get()
127  {
128  return Info::Metadata::uuid;
129  }
130 };
131 
132 namespace Control
133 {
134 
135 struct PortSetup
136 {
137  template <typename Node_T, typename T>
138  static void init(T& self)
139  {
140  auto& ins = self.m_inlets;
141  auto& outs = self.m_outlets;
142  int inlet = 0;
143  for(const auto& in : Node_T::Metadata::audio_ins)
144  {
145  auto p = new Process::AudioInlet(Id<Process::Port>(inlet++), &self);
146  p->setName(QString::fromUtf8(in.name.data(), in.name.size()));
147  ins.push_back(p);
148  }
149  for(const auto& in : Node_T::Metadata::midi_ins)
150  {
151  auto p = new Process::MidiInlet(Id<Process::Port>(inlet++), &self);
152  p->setName(QString::fromUtf8(in.name.data(), in.name.size()));
153  ins.push_back(p);
154  }
155  for(const auto& in : Node_T::Metadata::value_ins)
156  {
157  auto p = new Process::ValueInlet(Id<Process::Port>(inlet++), &self);
158  p->setName(QString::fromUtf8(in.name.data(), in.name.size()));
159  ins.push_back(p);
160  }
161  for(const auto& in : Node_T::Metadata::address_ins)
162  {
163  auto p = new Process::ValueInlet(Id<Process::Port>(inlet++), &self);
164  p->setName(QString::fromUtf8(in.name.data(), in.name.size()));
165  ins.push_back(p);
166  }
167  ossia::for_each_in_tuple(Node_T::Metadata::controls, [&](const auto& ctrl) {
168  if(auto p = ctrl.create_inlet(Id<Process::Port>(inlet++), &self))
169  {
170  p->hidden = true;
171  ins.push_back(p);
172  }
173  });
174 
175  int outlet = 0;
176  for(const auto& out : Node_T::Metadata::audio_outs)
177  {
178  auto p = new Process::AudioOutlet(Id<Process::Port>(outlet++), &self);
179  p->setName(QString::fromUtf8(out.name.data(), out.name.size()));
180  if(outlet == 1)
181  p->setPropagate(true);
182  outs.push_back(p);
183  }
184  for(const auto& out : Node_T::Metadata::midi_outs)
185  {
186  auto p = new Process::MidiOutlet(Id<Process::Port>(outlet++), &self);
187  p->setName(QString::fromUtf8(out.name.data(), out.name.size()));
188  outs.push_back(p);
189  }
190  for(const auto& out : Node_T::Metadata::value_outs)
191  {
192  auto p = new Process::ValueOutlet(Id<Process::Port>(outlet++), &self);
193  p->setName(QString::fromUtf8(out.name.data(), out.name.size()));
194  outs.push_back(p);
195  }
196  ossia::for_each_in_tuple(Node_T::Metadata::control_outs, [&](const auto& ctrl) {
197  if(auto p = ctrl.create_outlet(Id<Process::Port>(outlet++), &self))
198  {
199  p->hidden = true;
200  outs.push_back(p);
201  }
202  });
203  }
204 
205  template <typename Node_T, typename T>
206  static void load(DataStream::Deserializer& s, T& self)
207  {
208  auto& ins = self.m_inlets;
209  auto& outs = self.m_outlets;
210  for([[maybe_unused]] const auto& in : Node_T::Metadata::audio_ins)
211  {
212  ins.push_back(deserialize_known_interface<Process::AudioInlet>(s, &self));
213  }
214  for([[maybe_unused]] const auto& in : Node_T::Metadata::midi_ins)
215  {
216  ins.push_back(deserialize_known_interface<Process::MidiInlet>(s, &self));
217  }
218  for([[maybe_unused]] const auto& in : Node_T::Metadata::value_ins)
219  {
220  ins.push_back(deserialize_known_interface<Process::ValueInlet>(s, &self));
221  }
222  for([[maybe_unused]] const auto& in : Node_T::Metadata::address_ins)
223  {
224  ins.push_back(deserialize_known_interface<Process::ValueInlet>(s, &self));
225  }
226  ossia::for_each_in_tuple(Node_T::Metadata::controls, [&](const auto& ctrl) {
227  if(auto p = ctrl.create_inlet(s, &self))
228  {
229  p->hidden = true;
230  ins.push_back(p);
231  }
232  });
233 
234  for([[maybe_unused]] const auto& out : Node_T::Metadata::audio_outs)
235  {
236  outs.push_back(deserialize_known_interface<Process::AudioOutlet>(s, &self));
237  }
238  for([[maybe_unused]] const auto& out : Node_T::Metadata::midi_outs)
239  {
240  outs.push_back(deserialize_known_interface<Process::MidiOutlet>(s, &self));
241  }
242  for([[maybe_unused]] const auto& out : Node_T::Metadata::value_outs)
243  {
244  outs.push_back(deserialize_known_interface<Process::ValueOutlet>(s, &self));
245  }
246  ossia::for_each_in_tuple(Node_T::Metadata::control_outs, [&](const auto& ctrl) {
247  if(auto p = ctrl.create_outlet(s, &self))
248  {
249  p->hidden = true;
250  outs.push_back(p);
251  }
252  });
253  }
254 
255  template <typename Node_T, typename T>
256  static void load(
257  const rapidjson::Value::ConstArray& inlets,
258  const rapidjson::Value::ConstArray& outlets, T& self)
259  {
260  auto& ins = self.m_inlets;
261  auto& outs = self.m_outlets;
262  int inlet = 0;
263  for([[maybe_unused]] const auto& in : Node_T::Metadata::audio_ins)
264  {
265  ins.push_back(deserialize_known_interface<Process::AudioInlet>(
266  JSONWriter{inlets[inlet++]}, &self));
267  }
268  for([[maybe_unused]] const auto& in : Node_T::Metadata::midi_ins)
269  {
270  ins.push_back(deserialize_known_interface<Process::MidiInlet>(
271  JSONWriter{inlets[inlet++]}, &self));
272  }
273  for([[maybe_unused]] const auto& in : Node_T::Metadata::value_ins)
274  {
275  ins.push_back(deserialize_known_interface<Process::ValueInlet>(
276  JSONWriter{inlets[inlet++]}, &self));
277  }
278  for([[maybe_unused]] const auto& in : Node_T::Metadata::address_ins)
279  {
280  ins.push_back(deserialize_known_interface<Process::ValueInlet>(
281  JSONWriter{inlets[inlet++]}, &self));
282  }
283  ossia::for_each_in_tuple(Node_T::Metadata::controls, [&](const auto& ctrl) {
284  if(auto p = ctrl.create_inlet(JSONWriter{inlets[inlet++]}, &self))
285  {
286  p->hidden = true;
287  ins.push_back(p);
288  }
289  });
290 
291  int outlet = 0;
292  for([[maybe_unused]] const auto& out : Node_T::Metadata::audio_outs)
293  {
294  outs.push_back(deserialize_known_interface<Process::AudioOutlet>(
295  JSONWriter{outlets[outlet++]}, &self));
296  }
297  for([[maybe_unused]] const auto& out : Node_T::Metadata::midi_outs)
298  {
299  outs.push_back(deserialize_known_interface<Process::MidiOutlet>(
300  JSONWriter{outlets[outlet++]}, &self));
301  }
302  for([[maybe_unused]] const auto& out : Node_T::Metadata::value_outs)
303  {
304  outs.push_back(deserialize_known_interface<Process::ValueOutlet>(
305  JSONWriter{outlets[outlet++]}, &self));
306  }
307  ossia::for_each_in_tuple(Node_T::Metadata::control_outs, [&](const auto& ctrl) {
308  if(auto p = ctrl.create_outlet(JSONWriter{outlets[outlet++]}, &self))
309  {
310  p->hidden = true;
311  outs.push_back(p);
312  }
313  });
314  }
315 };
316 
317 template <typename Info, typename>
319 {
320  SCORE_SERIALIZE_FRIENDS
321  PROCESS_METADATA_IMPL(ControlProcess<Info>)
322  friend struct TSerializer<DataStream, Control::ControlProcess<Info>>;
323  friend struct TSerializer<JSONObject, Control::ControlProcess<Info>>;
324  friend struct Control::PortSetup;
325 
326 public:
327  ossia::value control(std::size_t i) const
328  {
329  static_assert(ossia::safe_nodes::info_functions<Info>::control_count != 0);
330  constexpr auto start = ossia::safe_nodes::info_functions<Info>::control_start;
331 
332  return static_cast<Process::ControlInlet*>(m_inlets[start + i])->value();
333  }
334 
335  void setControl(std::size_t i, ossia::value v)
336  {
337  static_assert(ossia::safe_nodes::info_functions<Info>::control_count != 0);
338  constexpr auto start = ossia::safe_nodes::info_functions<Info>::control_start;
339 
340  static_cast<Process::ControlInlet*>(m_inlets[start + i])
341  ->setExecutionValue(std::move(v));
342  }
343 
344  ossia::value controlOut(std::size_t i) const
345  {
346  static_assert(ossia::safe_nodes::info_functions<Info>::control_out_count != 0);
347  constexpr auto start = ossia::safe_nodes::info_functions<Info>::control_out_start;
348 
349  return static_cast<Process::ControlOutlet*>(m_outlets[start + i])->value();
350  }
351 
352  void setControlOut(std::size_t i, ossia::value v)
353  {
354  static_assert(ossia::safe_nodes::info_functions<Info>::control_out_count != 0);
355  constexpr auto start = ossia::safe_nodes::info_functions<Info>::control_out_start;
356 
357  static_cast<Process::ControlOutlet*>(m_outlets[start + i])
358  ->setExecutionValue(std::move(v));
359  }
360 
362  const TimeVal& duration, const Id<Process::ProcessModel>& id, QObject* parent)
364  duration, id, Metadata<ObjectKey_k, ProcessModel>::get(), parent}
365  {
366  metadata().setInstanceName(*this);
367 
368  Control::PortSetup::init<Info>(*this);
369 
370  if constexpr(requires { Info::Metadata::loops_by_default; })
371  {
372  setLoops(true);
373  }
374  }
375 
376  template <typename Impl>
377  explicit ControlProcess(Impl& vis, QObject* parent)
378  : Process::ProcessModel{vis, parent}
379  {
380  vis.writeTo(*this);
381  }
382 
383  ~ControlProcess() override { }
384 };
385 }
386 
387 template <typename Info>
388 struct is_custom_serialized<Control::ControlProcess<Info>> : std::true_type
389 {
390 };
391 
392 template <template <typename, typename> class Model, typename Info>
393 struct TSerializer<DataStream, Model<Info, Control::is_control>>
394 {
395  using model_type = Model<Info, Control::is_control>;
396  static void readFrom(DataStream::Serializer& s, const model_type& obj)
397  {
398  using namespace Control;
399  for(auto obj : obj.inlets())
400  {
401  s.stream() << *obj;
402  }
403 
404  for(auto obj : obj.outlets())
405  {
406  s.stream() << *obj;
407  }
408  s.insertDelimiter();
409  }
410 
411  static void writeTo(DataStream::Deserializer& s, model_type& obj)
412  {
413  using namespace Control;
414 
415  Control::PortSetup::load<Info>(s, obj);
416  s.checkDelimiter();
417  }
418 };
419 
420 template <template <typename, typename> class Model, typename Info>
421 struct TSerializer<JSONObject, Model<Info, Control::is_control>>
422 {
423  using model_type = Model<Info, Control::is_control>;
424  static void readFrom(JSONObject::Serializer& s, const model_type& obj)
425  {
426  using namespace Control;
427  Process::readPorts(s, obj.inlets(), obj.outlets());
428  }
429 
430  static void writeTo(JSONObject::Deserializer& s, model_type& obj)
431  {
432  using namespace Control;
433 
434  const auto& inlets = s.obj["Inlets"].toArray();
435  const auto& outlets = s.obj["Outlets"].toArray();
436 
437  Control::PortSetup::load<Info>(inlets, outlets, obj);
438  }
439 };
Metadata to categorize objects: curves, audio, etc.
Definition: lib/score/tools/Metadata.hpp:61
Definition: score-plugin-engine/Engine/Node/Process.hpp:319
Definition: VisitorInterface.hpp:53
Definition: DataStreamVisitor.hpp:27
Definition: DataStreamVisitor.hpp:202
Definition: VisitorInterface.hpp:61
Definition: JSONVisitor.hpp:52
Definition: JSONVisitor.hpp:423
Metadata to get the key part of ObjectIdentifier.
Definition: lib/score/tools/Metadata.hpp:36
Metadata to get the name that will be shown in the user interface.
Definition: lib/score/tools/Metadata.hpp:42
Definition: score-lib-process/Process/Dataflow/Port.hpp:290
Definition: score-lib-process/Process/Dataflow/Port.hpp:313
Definition: score-lib-process/Process/Dataflow/Port.hpp:202
Definition: score-lib-process/Process/Dataflow/Port.hpp:415
Definition: score-lib-process/Process/Dataflow/Port.hpp:369
Definition: score-lib-process/Process/Dataflow/Port.hpp:392
The Process class.
Definition: score-lib-process/Process/Process.hpp:61
Definition: score-lib-process/Process/Dataflow/Port.hpp:481
Definition: score-lib-process/Process/Dataflow/Port.hpp:504
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
Base classes and tools to implement processes and layers.
Definition: JSONVisitor.hpp:1324
ProcessFlags
Various settings for processes.
Definition: ProcessFlags.hpp:17
Definition: score-plugin-engine/Engine/Node/Process.hpp:136
Definition: score-plugin-engine/Engine/Node/Process.hpp:22
Static metadata implementation.
Definition: lib/score/tools/Metadata.hpp:36
Definition: score-lib-process/Process/ProcessMetadata.hpp:36
Definition: VisitorInterface.hpp:13
Definition: TimeValue.hpp:21