Loading...
Searching...
No Matches
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#include <Engine/Node/CommonWidgets.hpp>
8
9#include <score/plugins/UuidKey.hpp>
10
11#include <ossia/dataflow/audio_port.hpp>
12#include <ossia/dataflow/port.hpp>
13#include <ossia/dataflow/safe_nodes/tick_policies.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 <span>
34#include <type_traits>
35
36#define make_uuid(text) score::uuids::string_generator::compute((text))
37
38namespace oscr
39{
40template <typename Node, typename FieldIndex>
41struct CustomFloatControl;
42}
43
44template <typename Node, typename FieldIndex>
45struct is_custom_serialized<oscr::CustomFloatControl<Node, FieldIndex>> : std::true_type
46{
47};
48
49namespace oscr
50{
51
53{
54 using Process::ControlInlet::ControlInlet;
55
57 float min, float max, float init, const QString& name, Id<Process::Port> id,
58 QObject* parent)
59 : ControlInlet{name, id, parent}
60 {
61 displayHandledExplicitly = true;
62 setValue(init);
63 setInit(init);
64 setDomain(ossia::make_domain(min, max));
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, QObject* exec_context) 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
78template <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}
98template <typename Node, typename FieldIndex>
99struct 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
110template <typename Node, typename FieldIndex>
111struct 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
122namespace oscr
123{
124
125template <typename Node, typename T, std::size_t N>
126static inline auto
127make_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::folder)
199 {
200 if constexpr(avnd::has_range<T>) {
201 static constexpr auto c = avnd::get_range<T>();
202#if defined(_MSC_VER)
203 auto init = std::begin(c.init);
204 if constexpr(std::is_same_v<std::decay_t<decltype(init)>, const char*>)
205 return new Process::FolderChooser{QString::fromUtf8(init, std::size(c.init)), qname, id, parent};
206 else
207 return new Process::FolderChooser{QString::fromUtf8(c.init.data(), c.init.size()), qname, id, parent};
208#else
209 return new Process::FolderChooser{
210 QString::fromUtf8(&*std::begin(c.init), std::size(c.init)), qname, id, parent};
211#endif
212 } else {
213 return new Process::FolderChooser{"", qname, id, parent};
214 }
215 }
216 else if constexpr(widg.widget == avnd::widget_type::range_slider)
217 {
218 static constexpr auto c = avnd::get_range<T>();
219 if constexpr(std::is_integral_v<value_type>)
220 {
221 auto [start, end] = c.init;
222 return new Process::IntRangeSlider{c.min, c.max, {(float)start, (float)end},
223 qname, id, parent};
224 }
225 else
226 {
227 auto [start, end] = c.init;
228 return new Process::FloatRangeSlider{c.min, c.max, {(float)start, (float)end},
229 qname, id, parent};
230 }
231 }
232 else if constexpr(widg.widget == avnd::widget_type::range_spinbox)
233 {
234 static constexpr auto c = avnd::get_range<T>();
235 if constexpr(std::is_integral_v<value_type>)
236 {
237 auto [start, end] = c.init;
238 return new Process::IntRangeSpinBox{c.min, c.max, {(float)start, (float)end},
239 qname, id, parent};
240 }
241 else
242 {
243 auto [start, end] = c.init;
244 return new Process::FloatRangeSpinBox{c.min, c.max, {(float)start, (float)end},
245 qname, id, parent};
246 }
247 }
248 else if constexpr(widg.widget == avnd::widget_type::multi_slider)
249 {
250 std::vector<ossia::value> init;
251 return new Process::MultiSlider{init, qname, id, parent};
252 }
253 else if constexpr(widg.widget == avnd::widget_type::multi_slider_xy)
254 {
255 std::vector<ossia::value> init;
256 return new Process::MultiSliderXY{init, qname, id, parent};
257 }
258 else if constexpr(widg.widget == avnd::widget_type::path_generator_xy)
259 {
260 std::vector<ossia::value> init;
261 return new Process::PathGeneratorXY{init, qname, id, parent};
262 }
263 else if constexpr(widg.widget == avnd::widget_type::spinbox)
264 {
265 static constexpr auto c = avnd::get_range<T>();
266 if constexpr(std::is_integral_v<value_type>)
267 {
268 return new Process::IntSpinBox{c.min, c.max, c.init, qname, id, parent};
269 }
270 else
271 {
272 return new Process::FloatSpinBox{c.min, c.max, c.init, qname, id, parent};
273 }
274 }
275 else if constexpr(widg.widget == avnd::widget_type::knob)
276 {
277 static constexpr auto c = avnd::get_range<T>();
278 if constexpr(std::is_integral_v<value_type>)
279 {
280 // FIXME do a IntKnob
281 return new Process::IntSlider{c.min, c.max, c.init, qname, id, parent};
282 }
283 else
284 {
285 if constexpr(avnd::has_mapper<T>)
286 {
287 return new CustomFloatControl<Node, avnd::field_index<N>>{c.min, c.max, c.init,
288 qname, id, parent};
289 }
290 else
291 {
292 return new Process::FloatKnob{c.min, c.max, c.init, qname, id, parent};
293 }
294 }
295 }
296 else if constexpr(widg.widget == avnd::widget_type::lineedit)
297 {
298 if constexpr(avnd::has_range<T>)
299 {
300 static constexpr auto c = avnd::get_range<T>();
301 if constexpr(avnd::program_parameter<T>)
302 {
303 auto p = new Process::ProgramEdit{c.init.data(), qname, id, parent};
304 p->language = T::language();
305 return p;
306 }
307 else
308 return new Process::LineEdit{c.init.data(), qname, id, parent};
309 }
310 else
311 {
312 if constexpr(avnd::program_parameter<T>)
313 {
314 auto p = new Process::ProgramEdit{"", qname, id, parent};
315 p->language = T::language();
316 return p;
317 }
318 else
319 return new Process::LineEdit{"", qname, id, parent};
320 }
321 }
322 else if constexpr(widg.widget == avnd::widget_type::combobox)
323 {
324 static constexpr auto c = avnd::get_range<T>();
325 using init_type = std::decay_t<decltype(c.init)>;
326 ossia::value init;
327 if constexpr(std::is_integral_v<init_type> || std::is_enum_v<init_type>)
328 init = static_cast<int>(c.init);
329 else
330 init = c.init;
331 return new Process::ComboBox{
332 to_combobox_range(c.values), std::move(init), qname, id, parent};
333 }
334 else if constexpr(widg.widget == avnd::widget_type::choices)
335 {
336 static constexpr auto c = avnd::get_range<T>();
337 auto enums = avnd::to_enum_range(c.values);
338 static_assert(
339 std::is_integral_v<decltype(c.init)> || std::is_enum_v<decltype(c.init)>);
340 auto init = enums[static_cast<int>(c.init)];
341 std::vector<QString> pixmaps;
342 if constexpr(avnd::has_pixmaps<T>)
343 {
344 for(std::string_view pix : avnd::get_pixmaps<T>())
345 {
346 pixmaps.push_back(QString::fromLatin1(pix.data(), pix.size()));
347 }
348 }
349 return new Process::Enum{
350 std::move(enums), pixmaps, std::move(init), qname, id, parent};
351 }
352 else if constexpr(widg.widget == avnd::widget_type::xy)
353 {
354 static constexpr auto c = avnd::get_range<T>();
355 if constexpr(requires {
356 c.min == 0.f;
357 c.max == 0.f;
358 c.init == 0.f;
359 })
360 {
361 return new Process::XYSlider{
362 {c.min, c.min}, {c.max, c.max}, {c.init, c.init}, qname, id, parent};
363 }
364 else
365 {
366 auto [mx, my] = c.min;
367 auto [Mx, My] = c.max;
368 auto [ix, iy] = c.init;
369 return new Process::XYSlider{{mx, my}, {Mx, My}, {ix, iy}, qname, id, parent};
370 }
371 }
372 else if constexpr(widg.widget == avnd::widget_type::xyz)
373 {
374 static constexpr auto c = avnd::get_range<T>();
375 if constexpr(requires {
376 c.min == 0.f;
377 c.max == 0.f;
378 c.init == 0.f;
379 })
380 {
381 return new Process::XYZSlider{
382 {c.min, c.min, c.min},
383 {c.max, c.max, c.max},
384 {c.init, c.init, c.init},
385 qname,
386 id,
387 parent};
388 }
389 else
390 {
391 auto [mx, my, mz] = c.min;
392 auto [Mx, My, Mz] = c.max;
393 auto [ix, iy, iz] = c.init;
394 return new Process::XYZSlider{{mx, my, mz}, {Mx, My, Mz}, {ix, iy, iz},
395 qname, id, parent};
396 }
397 }
398 else if constexpr(widg.widget == avnd::widget_type::xy_spinbox)
399 {
400 using data_type = std::decay_t<decltype(value_type{}.x)>;
401 static constexpr auto c = avnd::get_range<T>();
402 if constexpr(requires {
403 c.min == 0.f;
404 c.max == 0.f;
405 c.init == 0.f;
406 })
407 {
408 return new Process::XYSpinboxes{
409 {c.min, c.min},
410 {c.max, c.max},
411 {c.init, c.init},
412 std::is_integral_v<data_type>,
413 qname,
414 id,
415 parent};
416 }
417 else
418 {
419 auto [mx, my] = c.min;
420 auto [Mx, My] = c.max;
421 auto [ix, iy] = c.init;
422 return new Process::XYSpinboxes{
423 {mx, my}, {Mx, My}, {ix, iy}, std::is_integral_v<data_type>,
424 qname, id, parent};
425 }
426 }
427 else if constexpr(widg.widget == avnd::widget_type::xyz_spinbox)
428 {
429 static constexpr auto c = avnd::get_range<T>();
430 if constexpr(requires {
431 c.min == 0.f;
432 c.max == 0.f;
433 c.init == 0.f;
434 })
435 {
436 return new Process::XYZSpinboxes{
437 {c.min, c.min, c.min},
438 {c.max, c.max, c.max},
439 {c.init, c.init, c.init},
440 false,
441 qname,
442 id,
443 parent};
444 }
445 else
446 {
447 auto [mx, my, mz] = c.min;
448 auto [Mx, My, Mz] = c.max;
449 auto [ix, iy, iz] = c.init;
450 return new Process::XYZSpinboxes{{mx, my, mz}, {Mx, My, Mz}, {ix, iy, iz},
451 qname, id, parent};
452 }
453 }
454 else if constexpr(widg.widget == avnd::widget_type::color)
455 {
456 static constexpr auto c = avnd::get_range<T>();
457 static constexpr auto i = c.init;
458 return new Process::HSVSlider{{i.r, i.g, i.b, i.a}, qname, id, parent};
459 }
460 else if constexpr(widg.widget == avnd::widget_type::control)
461 {
462 return new Process::ControlInlet{qname, id, parent};
463 }
464 else if constexpr(widg.widget == avnd::widget_type::no_control)
465 {
466 return new Process::ValueInlet{qname, id, parent};
467 }
468 else
469 {
470 static_assert(T::is_not_a_valid_control);
471 }
472}
473
474template <typename T, std::size_t N>
475static inline auto
476make_control_out(avnd::field_index<N>, Id<Process::Port>&& id, QObject* parent)
477{
478 constexpr auto name = avnd::get_name<T>();
479 constexpr auto widg = avnd::get_widget<T>();
480 QString qname = QString::fromUtf8(name.data(), name.size());
481
482 // FIXME log normalization & friends
483
484 if constexpr(widg.widget == avnd::widget_type::bargraph)
485 {
486 static constexpr auto c = avnd::get_range<T>();
487 return new Process::Bargraph{c.min, c.max, c.init, qname, id, parent};
488 }
489 else if constexpr(widg.widget == avnd::widget_type::control)
490 {
491 return new Process::ControlOutlet{qname, id, parent};
492 }
493 else if constexpr(widg.widget == avnd::widget_type::no_control)
494 {
495 return new Process::ValueOutlet{qname, id, parent};
496 }
497 else if constexpr(avnd::fp_ish<decltype(T::value)>)
498 {
499 static constexpr auto c = avnd::get_range<T>();
500 return new Process::Bargraph{c.min, c.max, c.init, qname, id, parent};
501 }
502 else
503 {
504 return new Process::ControlOutlet{qname, id, parent};
505 }
506}
507
508template <typename T>
509static inline constexpr auto make_control_out(const T& t)
510{
511 return make_control_out<T>();
512}
513}
514
515namespace oscr
516{
518{
519 ossia::audio_vector* buffer{};
520 int64_t offset{};
521 int64_t duration{};
522
523 std::span<const double> operator[](std::size_t i) const noexcept
524 {
525 auto& chan = (*buffer)[i];
526 int64_t min_dur = std::min(int64_t(chan.size()) - offset, duration);
527 if(min_dur < 0)
528 min_dur = 0;
529
530 return std::span<const double>{chan.data() + offset, std::size_t(min_dur)};
531 }
532
533 std::size_t channels() const noexcept { return buffer->size(); }
534 void resize(std::size_t i) const noexcept { return buffer->resize(i); }
535 void reserve(std::size_t channels, std::size_t bufferSize)
536 {
537 resize(channels);
538 for(auto& vec : *buffer)
539 vec.reserve(bufferSize);
540 }
541};
542
544{
545 ossia::audio_vector* buffer{};
546 int64_t offset{};
547 int64_t duration{};
548
549 std::span<double> operator[](std::size_t i) const noexcept
550 {
551 auto& chan = (*buffer)[i];
552 int64_t min_dur = std::min(int64_t(chan.size()) - offset, duration);
553 if(min_dur < 0)
554 min_dur = 0;
555
556 return std::span<double>{chan.data() + offset, std::size_t(min_dur)};
557 }
558
559 std::size_t channels() const noexcept { return buffer->size(); }
560 void resize(std::size_t channels, std::size_t samples_to_write) const noexcept
561 {
562 buffer->resize(channels);
563 for(auto& c : *buffer)
564 c.resize(offset + samples_to_write);
565 }
566
567 void reserve(std::size_t channels, std::size_t bufferSize)
568 {
569 buffer->resize(channels);
570 for(auto& c : *buffer)
571 c.reserve(bufferSize);
572 }
573};
574
575}
Definition VisitorInterface.hpp:53
Definition DataStreamVisitor.hpp:27
void read(const T &)
Definition DataStreamVisitor.hpp:202
Definition VisitorInterface.hpp:61
Definition JSONVisitor.hpp:52
Definition JSONVisitor.hpp:423
Definition Port.hpp:206
Definition Port.hpp:427
Definition Port.hpp:493
Definition Port.hpp:516
Definition UuidKey.hpp:345
The id_base_t class.
Definition Identifier.hpp:59
Definition Factories.hpp:19
Definition CurveInlet.hpp:47
Definition WidgetInlets.hpp:646
Definition WidgetInlets.hpp:488
Definition WidgetInlets.hpp:335
Definition WidgetInlets.hpp:444
Definition WidgetInlets.hpp:464
Definition WidgetInlets.hpp:172
Definition WidgetInlets.hpp:233
Definition WidgetInlets.hpp:265
Definition WidgetInlets.hpp:158
Definition WidgetInlets.hpp:296
Definition WidgetInlets.hpp:393
Definition WidgetInlets.hpp:512
Definition WidgetInlets.hpp:499
Definition WidgetInlets.hpp:217
Definition WidgetInlets.hpp:249
Definition WidgetInlets.hpp:202
Definition WidgetInlets.hpp:281
Definition WidgetInlets.hpp:349
Definition WidgetInlets.hpp:187
Definition WidgetInlets.hpp:601
Definition WidgetInlets.hpp:616
Definition WidgetInlets.hpp:630
Definition WidgetInlets.hpp:431
Definition WidgetInlets.hpp:310
Definition WidgetInlets.hpp:324
Definition WidgetInlets.hpp:525
Definition WidgetInlets.hpp:559
Definition WidgetInlets.hpp:542
Definition WidgetInlets.hpp:583
Definition VisitorInterface.hpp:13
The VisitorVariant struct.
Definition VisitorInterface.hpp:26
Definition Concepts.hpp:53
Definition Concepts.hpp:80
Definition Concepts.hpp:518
Definition Concepts.hpp:544