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