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