Concepts.hpp
1 #pragma once
2 #include <Process/Dataflow/WidgetInlets.hpp>
3 #include <Process/ProcessFlags.hpp>
4 #include <Process/ProcessMetadata.hpp>
5 
6 #include <Dataflow/CurveInlet.hpp>
7 
8 #include <score/plugins/UuidKey.hpp>
9 
10 #include <ossia/dataflow/audio_port.hpp>
11 #include <ossia/dataflow/port.hpp>
12 #include <ossia/dataflow/safe_nodes/tick_policies.hpp>
13 #include <ossia/detail/span.hpp>
14 
15 #include <boost/container/vector.hpp>
16 
17 #include <avnd/binding/ossia/qt.hpp>
18 #include <avnd/binding/ossia/uuid.hpp>
19 #include <avnd/common/concepts_polyfill.hpp>
20 #include <avnd/common/struct_reflection.hpp>
21 #include <avnd/concepts/audio_port.hpp>
22 #include <avnd/concepts/channels.hpp>
23 #include <avnd/concepts/curve.hpp>
24 #include <avnd/concepts/gfx.hpp>
25 #include <avnd/concepts/midi_port.hpp>
26 #include <avnd/concepts/parameter.hpp>
27 #include <avnd/introspection/input.hpp>
28 #include <avnd/wrappers/metadatas.hpp>
29 #include <avnd/wrappers/widgets.hpp>
30 
31 #include <cmath>
32 
33 #include <type_traits>
34 
35 #define make_uuid(text) score::uuids::string_generator::compute((text))
36 
37 namespace oscr
38 {
39 template <typename Node, typename FieldIndex>
40 struct CustomFloatControl;
41 }
42 
43 template <typename Node, typename FieldIndex>
44 struct is_custom_serialized<oscr::CustomFloatControl<Node, FieldIndex>> : std::true_type
45 {
46 };
47 
48 namespace oscr
49 {
50 
52 {
53  using Process::ControlInlet::ControlInlet;
54 
56  float min, float max, float init, const QString& name, Id<Process::Port> id,
57  QObject* parent)
58  : ControlInlet{id, parent}
59  {
60  hidden = true;
61  setValue(init);
62  setInit(init);
63  setDomain(ossia::make_domain(min, max));
64  setName(name);
65  }
66 
67  auto getMin() const noexcept { return domain().get().template convert_min<float>(); }
68  auto getMax() const noexcept { return domain().get().template convert_max<float>(); }
69 
70  void setupExecution(ossia::inlet& inl) const noexcept override
71  {
72  auto& port = **safe_cast<ossia::value_inlet*>(&inl);
73  port.type = ossia::val_type::FLOAT;
74  port.domain = domain().get();
75  }
76 };
77 
78 template <typename Node, typename FieldIndex>
80 {
81  using CustomFloatControlBase::CustomFloatControlBase;
82 
83  static key_type static_concreteKey() noexcept
84  {
85  return make_field_uuid<Node>(true, FieldIndex{});
86  }
87  key_type concreteKey() const noexcept override { return static_concreteKey(); }
88 
89  void serialize_impl(const VisitorVariant& vis) const noexcept override
90  {
91  score::serialize_dyn(vis, *this);
92  }
93 
94  ~CustomFloatControl() = default;
95 };
96 
97 }
98 template <typename Node, typename FieldIndex>
99 struct TSerializer<DataStream, oscr::CustomFloatControl<Node, FieldIndex>>
100 {
102  static void readFrom(DataStream::Serializer& s, const model_type& p)
103  {
104  s.read((const Process::ControlInlet&)p);
105  }
106 
107  static void writeTo(DataStream::Deserializer& s, model_type& eff) { }
108 };
109 
110 template <typename Node, typename FieldIndex>
111 struct TSerializer<JSONObject, oscr::CustomFloatControl<Node, FieldIndex>>
112 {
114  static void readFrom(JSONObject::Serializer& s, const model_type& p)
115  {
116  s.read((const Process::ControlInlet&)p);
117  }
118 
119  static void writeTo(JSONObject::Deserializer& s, model_type& eff) { }
120 };
121 
122 namespace oscr
123 {
124 
125 template <typename Node, typename T, std::size_t N>
126 static inline auto
127 make_control_in(avnd::field_index<N>, Id<Process::Port>&& id, QObject* parent)
128 {
129  using value_type = as_type(T::value);
130  constexpr auto name = avnd::get_name<T>();
131  QString qname = QString::fromUtf8(name.data(), name.size());
132 
133  constexpr auto widg = avnd::get_widget<T>();
134 
135  // FIXME log normalization & friends
136 
137  if constexpr(avnd::curve_port<T>)
138  {
139  return new Dataflow::CurveInlet(id, parent);
140  }
141  else if constexpr(widg.widget == avnd::widget_type::bang)
142  {
143  return new Process::ImpulseButton{qname, id, parent};
144  }
145  else if constexpr(widg.widget == avnd::widget_type::button)
146  {
147  return new Process::Button{qname, id, parent};
148  }
149  else if constexpr(widg.widget == avnd::widget_type::toggle)
150  {
151  static constexpr auto c = avnd::get_range<T>();
152  if constexpr(requires { c.values(); })
153  {
154  return new Process::ChooserToggle{
155  {c.values[0], c.values[1]}, c.init, qname, id, parent};
156  }
157  else
158  {
159  return new Process::Toggle{bool(c.init), qname, id, parent};
160  }
161  }
162  else if constexpr(widg.widget == avnd::widget_type::slider)
163  {
164  static constexpr auto c = avnd::get_range<T>();
165  if constexpr(std::is_integral_v<value_type>)
166  {
167  return new Process::IntSlider{c.min, c.max, c.init, qname, id, parent};
168  }
169  else
170  {
171  if constexpr(avnd::has_mapper<T>)
172  {
173  return new CustomFloatControl<Node, avnd::field_index<N>>{c.min, c.max, c.init,
174  qname, id, parent};
175  }
176  else
177  {
178  return new Process::FloatSlider{c.min, c.max, c.init, qname, id, parent};
179  }
180  }
181  }
182  else if constexpr(widg.widget == avnd::widget_type::log_slider)
183  {
184  static constexpr auto c = avnd::get_range<T>();
185  return new Process::LogFloatSlider{c.min, c.max, c.init, qname, id, parent};
186  }
187  else if constexpr(widg.widget == avnd::widget_type::log_knob)
188  {
189  // FIXME
190  static constexpr auto c = avnd::get_range<T>();
191  return new Process::LogFloatSlider{c.min, c.max, c.init, qname, id, parent};
192  }
193  else if constexpr(widg.widget == avnd::widget_type::time_chooser)
194  {
195  static constexpr auto c = avnd::get_range<T>();
196  return new Process::TimeChooser{c.min, c.max, c.init, qname, id, parent};
197  }
198  else if constexpr(widg.widget == avnd::widget_type::range_slider)
199  {
200  static constexpr auto c = avnd::get_range<T>();
201  if constexpr(std::is_integral_v<value_type>)
202  {
203  auto [start, end] = c.init;
204  return new Process::IntRangeSlider{c.min, c.max, {(float)start, (float)end},
205  qname, id, parent};
206  }
207  else
208  {
209  auto [start, end] = c.init;
210  return new Process::FloatRangeSlider{c.min, c.max, {(float)start, (float)end},
211  qname, id, parent};
212  }
213  }
214  else if constexpr(widg.widget == avnd::widget_type::range_spinbox)
215  {
216  static constexpr auto c = avnd::get_range<T>();
217  if constexpr(std::is_integral_v<value_type>)
218  {
219  auto [start, end] = c.init;
220  return new Process::IntRangeSpinBox{c.min, c.max, {(float)start, (float)end},
221  qname, id, parent};
222  }
223  else
224  {
225  auto [start, end] = c.init;
226  return new Process::FloatRangeSpinBox{c.min, c.max, {(float)start, (float)end},
227  qname, id, parent};
228  }
229  }
230  else if constexpr(widg.widget == avnd::widget_type::multi_slider)
231  {
232  constexpr auto c = avnd::get_range<T>();
233  auto [start, end] = c.init;
234  std::vector<ossia::value> init;
235  return new Process::MultiSlider{init, qname, id, parent};
236  }
237  else if constexpr(widg.widget == avnd::widget_type::spinbox)
238  {
239  static constexpr auto c = avnd::get_range<T>();
240  if constexpr(std::is_integral_v<value_type>)
241  {
242  return new Process::IntSpinBox{c.min, c.max, c.init, qname, id, parent};
243  }
244  else
245  {
246  return new Process::FloatSpinBox{c.min, c.max, c.init, qname, id, parent};
247  }
248  }
249  else if constexpr(widg.widget == avnd::widget_type::knob)
250  {
251  static constexpr auto c = avnd::get_range<T>();
252  if constexpr(std::is_integral_v<value_type>)
253  {
254  // FIXME do a IntKnob
255  return new Process::IntSlider{c.min, c.max, c.init, qname, id, parent};
256  }
257  else
258  {
259  if constexpr(avnd::has_mapper<T>)
260  {
261  return new CustomFloatControl<Node, avnd::field_index<N>>{c.min, c.max, c.init,
262  qname, id, parent};
263  }
264  else
265  {
266  return new Process::FloatKnob{c.min, c.max, c.init, qname, id, parent};
267  }
268  }
269  }
270  else if constexpr(widg.widget == avnd::widget_type::lineedit)
271  {
272  if constexpr(avnd::has_range<T>)
273  {
274  static constexpr auto c = avnd::get_range<T>();
275  if constexpr(avnd::program_parameter<T>)
276  {
277  auto p = new Process::ProgramEdit{c.init.data(), qname, id, parent};
278  p->language = T::language();
279  return p;
280  }
281  else
282  return new Process::LineEdit{c.init.data(), qname, id, parent};
283  }
284  else
285  {
286  if constexpr(avnd::program_parameter<T>)
287  {
288  auto p = new Process::ProgramEdit{"", qname, id, parent};
289  p->language = T::language();
290  return p;
291  }
292  else
293  return new Process::LineEdit{"", qname, id, parent};
294  }
295  }
296  else if constexpr(widg.widget == avnd::widget_type::combobox)
297  {
298  static constexpr auto c = avnd::get_range<T>();
299  return new Process::ComboBox{to_combobox_range(c.values), c.init, qname, id, parent};
300  }
301  else if constexpr(widg.widget == avnd::widget_type::choices)
302  {
303  static constexpr auto c = avnd::get_range<T>();
304  auto enums = avnd::to_enum_range(c.values);
305  static_assert(
306  std::is_integral_v<decltype(c.init)> || std::is_enum_v<decltype(c.init)>);
307  auto init = enums[static_cast<int>(c.init)];
308  std::vector<QString> pixmaps;
309  if constexpr(avnd::has_pixmaps<T>)
310  {
311  for(std::string_view pix : avnd::get_pixmaps<T>())
312  {
313  pixmaps.push_back(QString::fromLatin1(pix.data(), pix.size()));
314  }
315  }
316  return new Process::Enum{
317  std::move(enums), pixmaps, std::move(init), qname, id, parent};
318  }
319  else if constexpr(widg.widget == avnd::widget_type::xy)
320  {
321  static constexpr auto c = avnd::get_range<T>();
322  if constexpr(requires {
323  c.min == 0.f;
324  c.max == 0.f;
325  c.init == 0.f;
326  })
327  {
328  return new Process::XYSlider{
329  {c.min, c.min}, {c.max, c.max}, {c.init, c.init}, qname, id, parent};
330  }
331  else
332  {
333  auto [mx, my] = c.min;
334  auto [Mx, My] = c.max;
335  auto [ix, iy] = c.init;
336  return new Process::XYSlider{{mx, my}, {Mx, My}, {ix, iy}, qname, id, parent};
337  }
338  }
339  else if constexpr(widg.widget == avnd::widget_type::xyz)
340  {
341  static constexpr auto c = avnd::get_range<T>();
342  if constexpr(requires {
343  c.min == 0.f;
344  c.max == 0.f;
345  c.init == 0.f;
346  })
347  {
348  return new Process::XYZSlider{
349  {c.min, c.min, c.min},
350  {c.max, c.max, c.max},
351  {c.init, c.init, c.init},
352  qname,
353  id,
354  parent};
355  }
356  else
357  {
358  auto [mx, my, mz] = c.min;
359  auto [Mx, My, Mz] = c.max;
360  auto [ix, iy, iz] = c.init;
361  return new Process::XYZSlider{{mx, my, mz}, {Mx, My, Mz}, {ix, iy, iz},
362  qname, id, parent};
363  }
364  }
365  else if constexpr(widg.widget == avnd::widget_type::xy_spinbox)
366  {
367  using data_type = std::decay_t<decltype(value_type{}.x)>;
368  static constexpr auto c = avnd::get_range<T>();
369  if constexpr(requires {
370  c.min == 0.f;
371  c.max == 0.f;
372  c.init == 0.f;
373  })
374  {
375  return new Process::XYSpinboxes{
376  {c.min, c.min},
377  {c.max, c.max},
378  {c.init, c.init},
379  std::is_integral_v<data_type>,
380  qname,
381  id,
382  parent};
383  }
384  else
385  {
386  auto [mx, my] = c.min;
387  auto [Mx, My] = c.max;
388  auto [ix, iy] = c.init;
389  return new Process::XYSpinboxes{
390  {mx, my}, {Mx, My}, {ix, iy}, std::is_integral_v<data_type>,
391  qname, id, parent};
392  }
393  }
394  else if constexpr(widg.widget == avnd::widget_type::xyz_spinbox)
395  {
396  static constexpr auto c = avnd::get_range<T>();
397  if constexpr(requires {
398  c.min == 0.f;
399  c.max == 0.f;
400  c.init == 0.f;
401  })
402  {
403  return new Process::XYZSpinboxes{
404  {c.min, c.min, c.min},
405  {c.max, c.max, c.max},
406  {c.init, c.init, c.init},
407  qname,
408  id,
409  parent};
410  }
411  else
412  {
413  auto [mx, my, mz] = c.min;
414  auto [Mx, My, Mz] = c.max;
415  auto [ix, iy, iz] = c.init;
416  return new Process::XYZSpinboxes{{mx, my, mz}, {Mx, My, Mz}, {ix, iy, iz},
417  qname, id, parent};
418  }
419  }
420  else if constexpr(widg.widget == avnd::widget_type::color)
421  {
422  static constexpr auto c = avnd::get_range<T>();
423  static constexpr auto i = c.init;
424  return new Process::HSVSlider{{i.r, i.g, i.b, i.a}, qname, id, parent};
425  }
426  else if constexpr(widg.widget == avnd::widget_type::control)
427  {
428  return new Process::ControlInlet{qname, id, parent};
429  }
430  else if constexpr(widg.widget == avnd::widget_type::no_control)
431  {
432  auto pv = new Process::ValueInlet{id, parent};
433  pv->setName(qname);
434  return pv;
435  }
436  else
437  {
438  static_assert(T::is_not_a_valid_control);
439  }
440 }
441 
442 template <typename T, std::size_t N>
443 static inline auto
444 make_control_out(avnd::field_index<N>, Id<Process::Port>&& id, QObject* parent)
445 {
446  constexpr auto name = avnd::get_name<T>();
447  constexpr auto widg = avnd::get_widget<T>();
448  QString qname = QString::fromUtf8(name.data(), name.size());
449 
450  // FIXME log normalization & friends
451 
452  if constexpr(widg.widget == avnd::widget_type::bargraph)
453  {
454  static constexpr auto c = avnd::get_range<T>();
455  return new Process::Bargraph{c.min, c.max, c.init, qname, id, parent};
456  }
457  else if constexpr(widg.widget == avnd::widget_type::control)
458  {
459  return new Process::ControlOutlet{qname, id, parent};
460  }
461  else if constexpr(widg.widget == avnd::widget_type::no_control)
462  {
463  auto pv = new Process::ValueOutlet{id, parent};
464  pv->setName(qname);
465  return pv;
466  }
467  else if constexpr(avnd::fp_ish<decltype(T::value)>)
468  {
469  static constexpr auto c = avnd::get_range<T>();
470  return new Process::Bargraph{c.min, c.max, c.init, qname, id, parent};
471  }
472  else
473  {
474  return new Process::ControlOutlet{qname, id, parent};
475  }
476 }
477 
478 template <typename T>
479 static inline constexpr auto make_control_out(const T& t)
480 {
481  return make_control_out<T>();
482 }
483 }
484 
485 namespace oscr
486 {
488 {
489  ossia::audio_vector* buffer{};
490  int64_t offset{};
491  int64_t duration{};
492 
493  tcb::span<const double> operator[](std::size_t i) const noexcept
494  {
495  auto& chan = (*buffer)[i];
496  int64_t min_dur = std::min(int64_t(chan.size()) - offset, duration);
497  if(min_dur < 0)
498  min_dur = 0;
499 
500  return tcb::span<const double>{chan.data() + offset, std::size_t(min_dur)};
501  }
502 
503  std::size_t channels() const noexcept { return buffer->size(); }
504  void resize(std::size_t i) const noexcept { return buffer->resize(i); }
505  void reserve(std::size_t channels, std::size_t bufferSize)
506  {
507  resize(channels);
508  for(auto& vec : *buffer)
509  vec.reserve(bufferSize);
510  }
511 };
512 
514 {
515  ossia::audio_vector* buffer{};
516  int64_t offset{};
517  int64_t duration{};
518 
519  tcb::span<double> operator[](std::size_t i) const noexcept
520  {
521  auto& chan = (*buffer)[i];
522  int64_t min_dur = std::min(int64_t(chan.size()) - offset, duration);
523  if(min_dur < 0)
524  min_dur = 0;
525 
526  return tcb::span<double>{chan.data() + offset, std::size_t(min_dur)};
527  }
528 
529  std::size_t channels() const noexcept { return buffer->size(); }
530  void resize(std::size_t channels, std::size_t samples_to_write) const noexcept
531  {
532  buffer->resize(channels);
533  for(auto& c : *buffer)
534  c.resize(offset + samples_to_write);
535  }
536 
537  void reserve(std::size_t channels, std::size_t bufferSize)
538  {
539  buffer->resize(channels);
540  for(auto& c : *buffer)
541  c.reserve(bufferSize);
542  }
543 };
544 
545 }
Definition: QmlObjects.hpp:114
Definition: VisitorInterface.hpp:53
Definition: DataStreamVisitor.hpp:27
Definition: DataStreamVisitor.hpp:202
Definition: VisitorInterface.hpp:61
Definition: JSONVisitor.hpp:52
Definition: JSONVisitor.hpp:423
Definition: Port.hpp:203
Definition: Port.hpp:425
Definition: Port.hpp:492
Definition: Port.hpp:515
Definition: UuidKey.hpp:343
The id_base_t class.
Definition: Identifier.hpp:57
Definition: Factories.hpp:19
Definition: CurveInlet.hpp:47
Definition: VisitorInterface.hpp:13
The VisitorVariant struct.
Definition: VisitorInterface.hpp:26
Definition: Concepts.hpp:52
Definition: Concepts.hpp:80
Definition: Concepts.hpp:488
Definition: Concepts.hpp:514