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
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
37namespace oscr
38{
39template <typename Node, typename FieldIndex>
40struct CustomFloatControl;
41}
42
43template <typename Node, typename FieldIndex>
44struct is_custom_serialized<oscr::CustomFloatControl<Node, FieldIndex>> : std::true_type
45{
46};
47
48namespace 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
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::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
442template <typename T, std::size_t N>
443static inline auto
444make_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
478template <typename T>
479static inline constexpr auto make_control_out(const T& t)
480{
481 return make_control_out<T>();
482}
483}
484
485namespace 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 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: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