Loading...
Searching...
No Matches
QmlObjects.hpp
1#pragma once
2#include <State/Domain.hpp>
3
4#include <Process/Dataflow/Port.hpp>
5#include <Process/Dataflow/WidgetInlets.hpp>
6
7#include <JS/Qml/QtMetatypes.hpp>
8
9#include <libremidi/detail/conversion.hpp>
10
11#if defined(SCORE_HAS_GPU_JS)
12#include <Gfx/TexturePort.hpp>
13
14#endif
15
16#include <score/tools/Debug.hpp>
17
18#include <ossia/detail/math.hpp>
19#include <ossia/detail/ssize.hpp>
20#include <ossia/network/domain/domain.hpp>
21
22#include <ossia-qt/js_utilities.hpp>
23
24#include <QJSValue>
25#include <QObject>
26#include <QQuickItem>
27#include <QQmlListProperty>
28#include <QVariant>
29#include <QVector>
30
31#include <libremidi/message.hpp>
32#include <libremidi/ump.hpp>
33
34#include <score_plugin_js_export.h>
35#include <wobjectimpl.h>
36
37#include <verdigris>
38
39class QQuickItem;
40namespace JS
41{
42class SCORE_PLUGIN_JS_EXPORT Inlet : public QObject
43{
44 W_OBJECT(Inlet)
45
46public:
47 using QObject::QObject;
48 virtual ~Inlet() override;
49 virtual Process::Inlet* make(Id<Process::Port>&& id, QObject*) = 0;
50 virtual bool isEvent() const { return false; }
51
52 W_INLINE_PROPERTY_CREF(QString, address, {}, address, setAddress, addressChanged)
53};
54
55class SCORE_PLUGIN_JS_EXPORT Outlet : public QObject
56{
57 W_OBJECT(Outlet)
58
59public:
60 using QObject::QObject;
61 virtual ~Outlet() override;
62 virtual Process::Outlet* make(Id<Process::Port>&& id, QObject*) = 0;
63
64 W_INLINE_PROPERTY_CREF(QString, address, {}, address, setAddress, addressChanged)
65};
66
67struct SCORE_PLUGIN_JS_EXPORT InValueMessage
68{
69 W_GADGET(InValueMessage)
70
71public:
72 qreal timestamp;
73 QVariant value;
74 W_PROPERTY(qreal, timestamp MEMBER timestamp)
75 W_PROPERTY(QVariant, value MEMBER value)
76};
77
78struct SCORE_PLUGIN_JS_EXPORT OutValueMessage
79{
80 W_GADGET(OutValueMessage)
81
82public:
83 qreal timestamp;
84 QJSValue value;
85 W_PROPERTY(qreal, timestamp MEMBER timestamp)
86 W_PROPERTY(QJSValue, value MEMBER value)
87};
88
89class SCORE_PLUGIN_JS_EXPORT ValueInlet : public Inlet
90{
91 W_OBJECT(ValueInlet)
92
93 QVariant m_value;
94 QVariantList m_values;
95
96public:
97 explicit ValueInlet(QObject* parent = nullptr);
98 virtual ~ValueInlet() override;
99 QVariant value() const;
100 QVariantList values() const { return m_values; }
101
102 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
103 {
104 return new Process::ValueInlet(objectName(), id, parent);
105 }
106
107 int length() const noexcept;
108 W_SLOT(length)
109
110 QVariant at(int index) const noexcept;
111 W_SLOT(at)
112
113 void clear() { m_values.clear(); }
114 void setValue(QVariant value);
115 void addValue(QVariant&& val) { m_values.append(std::move(val)); }
116 void valueChanged(QVariant value) W_SIGNAL(valueChanged, value);
117
118 W_PROPERTY(QVariantList, values READ values)
119 W_PROPERTY(QVariant, value READ value NOTIFY valueChanged)
120};
121
122class SCORE_PLUGIN_JS_EXPORT ControlInlet : public Inlet
123{
124 W_OBJECT(ControlInlet)
125
126 QVariant m_value;
127
128public:
129 explicit ControlInlet(QObject* parent = nullptr);
130 virtual ~ControlInlet() override;
131 QVariant value() const noexcept;
132
133 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
134 {
135 return new Process::ControlInlet(objectName(), id, parent);
136 }
137
138 void clear() { m_value = QVariant{}; }
139 virtual void setValue(QVariant value);
140 void valueChanged(QVariant value) W_SIGNAL(valueChanged, value);
141
142 W_PROPERTY(QVariant, value READ value NOTIFY valueChanged)
143};
144
145template <typename Impl, typename ValueType, typename OssiaType>
146class SCORE_PLUGIN_JS_EXPORT GenericControlInlet : public ControlInlet
147{
148 W_OBJECT(GenericControlInlet)
149
150public:
151 using ControlInlet::ControlInlet;
152 virtual ~GenericControlInlet() override = default;
153 bool isEvent() const override { return true; }
154 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
155 {
156 return new Impl(objectName(), id, parent);
157 }
158
159 void clear() { m_value = {}; }
160 ValueType value() const noexcept { return m_value; }
161 void setValue(QVariant value) override
162 {
163 auto conv = value.value<ValueType>();
164 if(m_value == conv)
165 return;
166
167 m_value = std::move(conv);
168 valueChanged(m_value);
169 }
170 void setValue(ValueType value)
171 {
172 if(m_value == value)
173 return;
174
175 m_value = value;
176 valueChanged(m_value);
177 }
178 void valueChanged(ValueType value) W_SIGNAL(valueChanged, value);
179
180 W_PROPERTY(ValueType, value READ value NOTIFY valueChanged)
181
182protected:
183 ValueType m_value{};
184};
185W_OBJECT_IMPL(
186 (GenericControlInlet<A, B, C>), template <typename A, typename B, typename C>)
187struct SCORE_PLUGIN_JS_EXPORT MultiSlider
189 Process::MultiSlider, QVector<qreal>, std::vector<ossia::value>>
190{
191 W_OBJECT(MultiSlider);
192 using GenericControlInlet::GenericControlInlet;
193};
194struct SCORE_PLUGIN_JS_EXPORT FileChooser
195 : JS::GenericControlInlet<Process::FileChooser, QString, std::string>
196{
197 W_OBJECT(FileChooser);
198 using GenericControlInlet::GenericControlInlet;
199};
200struct SCORE_PLUGIN_JS_EXPORT AudioFileChooser
201 : JS::GenericControlInlet<Process::AudioFileChooser, QString, std::string>
202{
203 W_OBJECT(AudioFileChooser);
204 using GenericControlInlet::GenericControlInlet;
205};
206struct SCORE_PLUGIN_JS_EXPORT VideoFileChooser
207 : JS::GenericControlInlet<Process::VideoFileChooser, QString, std::string>
208{
209 W_OBJECT(VideoFileChooser);
210 using GenericControlInlet::GenericControlInlet;
211};
212
213template <typename Impl = Process::FloatSlider>
214class SCORE_PLUGIN_JS_EXPORT FloatSlider : public GenericControlInlet<Impl, float, float>
215{
216 W_OBJECT(FloatSlider)
217
218public:
219 using GenericControlInlet<Impl, float, float>::GenericControlInlet;
220 virtual ~FloatSlider() override = default;
221 bool isEvent() const override { return true; }
222
223 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
224 {
225 return new Impl{(float)m_min, (float)m_max, (float)m_init,
226 this->objectName(), id, parent};
227 }
228
229 W_INLINE_PROPERTY_VALUE(qreal, init, {0.5}, init, setInit, initChanged)
230 W_INLINE_PROPERTY_VALUE(qreal, min, {0.}, getMin, setMin, minChanged)
231 W_INLINE_PROPERTY_VALUE(qreal, max, {1.}, getMax, setMax, maxChanged)
232};
233W_OBJECT_IMPL(JS::FloatSlider<Impl>, template <typename Impl>)
234
235template <typename Impl = Process::IntSlider>
236class SCORE_PLUGIN_JS_EXPORT IntSlider : public GenericControlInlet<Impl, int, int>
237{
238 W_OBJECT(IntSlider)
239
240public:
241 using GenericControlInlet<Impl, int, int>::GenericControlInlet;
242 virtual ~IntSlider() override = default;
243 bool isEvent() const override { return true; }
244
245 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
246 {
247 return new Impl{m_min, m_max, m_init, this->objectName(), id, parent};
248 }
249
250 W_INLINE_PROPERTY_VALUE(int, init, {0}, init, setInit, initChanged)
251 W_INLINE_PROPERTY_VALUE(int, min, {0}, getMin, setMin, minChanged)
252 W_INLINE_PROPERTY_VALUE(int, max, {127}, getMax, setMax, maxChanged)
253};
254W_OBJECT_IMPL(JS::IntSlider<Impl>, template <typename Impl>)
255
256static constexpr auto vec2(double v)
257{
258 return QVector2D{(float)v, (float)v};
259}
260static constexpr auto vec3(double v)
261{
262 return QVector3D{(float)v, (float)v, (float)v};
263}
264static constexpr auto vec4(double v)
265{
266 return QVector4D{(float)v, (float)v, (float)v, (float)v};
267}
268static constexpr auto vec_to_ossia(QVector2D v)
269{
270 return ossia::vec2f{(float)v[0], (float)v[1]};
271}
272static constexpr auto vec_to_ossia(QVector3D v)
273{
274 return ossia::vec3f{(float)v[0], (float)v[1], (float)v[2]};
275}
276static constexpr auto vec_to_ossia(QVector4D v)
277{
278 return ossia::vec4f{(float)v[0], (float)v[1], (float)v[2], (float)v[3]};
279}
280
281template <typename Impl>
282class SCORE_PLUGIN_JS_EXPORT FloatControl2D
283 : public GenericControlInlet<Impl, QVector2D, ossia::vec2f>
284{
285 W_OBJECT(FloatControl2D)
286
287public:
288 using GenericControlInlet<Impl, QVector2D, ossia::vec2f>::GenericControlInlet;
289 virtual ~FloatControl2D() override = default;
290 bool isEvent() const override { return true; }
291
292 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
293 {
294 if constexpr(std::is_constructible_v<
295 Impl, ossia::vec2f, ossia::vec2f, ossia::vec2f, bool, QString,
296 Id<Process::Port>, QObject*>)
297 return new Impl{
298 vec_to_ossia(m_min),
299 vec_to_ossia(m_max),
300 vec_to_ossia(m_init),
301 false,
302 this->objectName(),
303 id,
304 parent};
305 else if constexpr(std::is_constructible_v<
306 Impl, ossia::vec2f, ossia::vec2f, ossia::vec2f, QString,
307 Id<Process::Port>, QObject*>)
308 return new Impl{
309 vec_to_ossia(m_min),
310 vec_to_ossia(m_max),
311 vec_to_ossia(m_init),
312 this->objectName(),
313 id,
314 parent};
315 else
316 return new Impl{vec_to_ossia(m_init), this->objectName(), id, parent};
317 }
318
319 W_INLINE_PROPERTY_VALUE(QVector2D, init, {vec2(0.)}, init, setInit, initChanged);
320 W_INLINE_PROPERTY_VALUE(QVector2D, min, {vec2(0.)}, getMin, setMin, minChanged);
321 W_INLINE_PROPERTY_VALUE(QVector2D, max, {vec2(1.)}, getMax, setMax, maxChanged);
322};
323W_OBJECT_IMPL(JS::FloatControl2D<Impl>, template <typename Impl>)
324
325template <typename Impl>
326class SCORE_PLUGIN_JS_EXPORT IntControl2D
327 : public GenericControlInlet<Impl, QVector2D, ossia::vec2f>
328{
329 W_OBJECT(IntControl2D)
330
331public:
332 using GenericControlInlet<Impl, QVector2D, ossia::vec2f>::GenericControlInlet;
333 virtual ~IntControl2D() override = default;
334 bool isEvent() const override { return true; }
335
336 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
337 {
338 return new Impl{
339 vec_to_ossia(m_min),
340 vec_to_ossia(m_max),
341 vec_to_ossia(m_init),
342 true,
343 this->objectName(),
344 id,
345 parent};
346 }
347
348 W_INLINE_PROPERTY_VALUE(QVector2D, init, {vec2(0.)}, init, setInit, initChanged);
349 W_INLINE_PROPERTY_VALUE(QVector2D, min, {vec2(0.)}, getMin, setMin, minChanged);
350 W_INLINE_PROPERTY_VALUE(QVector2D, max, {vec2(1.)}, getMax, setMax, maxChanged);
351};
352W_OBJECT_IMPL(JS::IntControl2D<Impl>, template <typename Impl>)
353
354template <typename Impl>
355class SCORE_PLUGIN_JS_EXPORT FloatControl1D_2D
356 : public GenericControlInlet<Impl, QVector2D, ossia::vec2f>
357{
358 W_OBJECT(FloatControl1D_2D)
359
360public:
361 using GenericControlInlet<Impl, QVector2D, ossia::vec2f>::GenericControlInlet;
362 virtual ~FloatControl1D_2D() override = default;
363 bool isEvent() const override { return true; }
364
365 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
366 {
367 return new Impl(m_min, m_max, vec_to_ossia(m_init), this->objectName(), id, parent);
368 }
369
370 W_INLINE_PROPERTY_VALUE(QVector2D, init, {vec2(0.)}, init, setInit, initChanged);
371 W_INLINE_PROPERTY_VALUE(float, min, {0.}, getMin, setMin, minChanged);
372 W_INLINE_PROPERTY_VALUE(float, max, {1.}, getMax, setMax, maxChanged);
373};
374W_OBJECT_IMPL(JS::FloatControl1D_2D<Impl>, template <typename Impl>)
375
376template <typename Impl>
377class SCORE_PLUGIN_JS_EXPORT FloatControl3D
378 : public GenericControlInlet<Impl, QVector3D, ossia::vec3f>
379{
380 W_OBJECT(FloatControl3D)
381
382public:
383 using GenericControlInlet<Impl, QVector3D, ossia::vec3f>::GenericControlInlet;
384 virtual ~FloatControl3D() override = default;
385 bool isEvent() const override { return true; }
386
387 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
388 {
389 if constexpr(std::is_constructible_v<
390 Impl, ossia::vec3f, ossia::vec3f, ossia::vec3f, bool, QString,
391 Id<Process::Port>, QObject*>)
392 return new Impl{
393 vec_to_ossia(m_min),
394 vec_to_ossia(m_max),
395 vec_to_ossia(m_init),
396 false,
397 this->objectName(),
398 id,
399 parent};
400 else if constexpr(std::is_constructible_v<
401 Impl, ossia::vec3f, ossia::vec3f, ossia::vec3f, QString,
402 Id<Process::Port>, QObject*>)
403 return new Impl{
404 vec_to_ossia(m_min),
405 vec_to_ossia(m_max),
406 vec_to_ossia(m_init),
407 this->objectName(),
408 id,
409 parent};
410 else
411 return new Impl{vec_to_ossia(m_init), this->objectName(), id, parent};
412 }
413
414 W_INLINE_PROPERTY_VALUE(QVector3D, init, {vec3(0.)}, init, setInit, initChanged);
415 W_INLINE_PROPERTY_VALUE(QVector3D, min, {vec3(0.)}, getMin, setMin, minChanged);
416 W_INLINE_PROPERTY_VALUE(QVector3D, max, {vec3(1.)}, getMax, setMax, maxChanged);
417};
418W_OBJECT_IMPL(JS::FloatControl3D<Impl>, template <typename Impl>)
419
420template <typename Impl>
421class SCORE_PLUGIN_JS_EXPORT IntControl3D
422 : public GenericControlInlet<Impl, QVector3D, ossia::vec3f>
423{
424 W_OBJECT(IntControl3D)
425
426public:
427 using GenericControlInlet<Impl, QVector3D, ossia::vec3f>::GenericControlInlet;
428 virtual ~IntControl3D() override = default;
429 bool isEvent() const override { return true; }
430
431 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
432 {
433 return new Impl{
434 vec_to_ossia(m_min),
435 vec_to_ossia(m_max),
436 vec_to_ossia(m_init),
437 true,
438 this->objectName(),
439 id,
440 parent};
441 }
442
443 W_INLINE_PROPERTY_VALUE(QVector3D, init, {vec3(0.)}, init, setInit, initChanged);
444 W_INLINE_PROPERTY_VALUE(QVector3D, min, {vec3(0.)}, getMin, setMin, minChanged);
445 W_INLINE_PROPERTY_VALUE(QVector3D, max, {vec3(1.)}, getMax, setMax, maxChanged);
446};
447W_OBJECT_IMPL(JS::IntControl3D<Impl>, template <typename Impl>)
448
449template <typename Impl>
450class SCORE_PLUGIN_JS_EXPORT FloatControl4D
451 : public GenericControlInlet<Impl, QVector4D, ossia::vec4f>
452{
453 W_OBJECT(FloatControl4D)
454
455public:
456 using GenericControlInlet<Impl, QVector4D, ossia::vec4f>::GenericControlInlet;
457 virtual ~FloatControl4D() override = default;
458 bool isEvent() const override { return true; }
459
460 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
461 {
462 if constexpr(std::is_constructible_v<
463 Impl, ossia::vec4f, ossia::vec4f, ossia::vec4f, QString,
464 Id<Process::Port>, QObject*>)
465 return new Impl{
466 vec_to_ossia(m_min),
467 vec_to_ossia(m_max),
468 vec_to_ossia(m_init),
469 this->objectName(),
470 id,
471 parent};
472 else
473 return new Impl{vec_to_ossia(m_init), this->objectName(), id, parent};
474 }
475
476 W_INLINE_PROPERTY_VALUE(QVector4D, init, {vec4(0.)}, init, setInit, initChanged);
477 W_INLINE_PROPERTY_VALUE(QVector4D, min, {vec4(0.)}, getMin, setMin, minChanged);
478 W_INLINE_PROPERTY_VALUE(QVector4D, max, {vec4(1.)}, getMax, setMax, maxChanged);
479};
480W_OBJECT_IMPL(JS::FloatControl4D<Impl>, template <typename Impl>)
481
482class SCORE_PLUGIN_JS_EXPORT Enum : public ControlInlet
483{
484 W_OBJECT(Enum)
485
486public:
487 using ControlInlet::ControlInlet;
488 virtual ~Enum() override;
489 bool isEvent() const override { return true; }
490
491 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
492 {
493 return new Process::Enum{m_choices, {}, current(), objectName(), id, parent};
494 }
495
496 auto getValues() const { return choices(); }
497
498 std::string current() const
499 {
500 if(!m_choices.isEmpty() && ossia::valid_index(m_index, m_choices))
501 {
502 return m_choices[m_index].toStdString();
503 }
504 return {};
505 }
506
507 W_INLINE_PROPERTY_VALUE(int, index, {}, index, setIndex, indexChanged)
508 W_INLINE_PROPERTY_CREF(QStringList, choices, {}, choices, setChoices, choicesChanged)
509};
510
511class SCORE_PLUGIN_JS_EXPORT ComboBox : public ControlInlet
512{
513 W_OBJECT(ComboBox)
514
515public:
516 using ControlInlet::ControlInlet;
517 virtual ~ComboBox() override;
518 bool isEvent() const override { return true; }
519
520 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
521 {
522 std::vector<std::pair<QString, ossia::value>> choices;
523 choices.reserve(m_choices.size());
524 for(auto& c : m_choices)
525 choices.emplace_back(c, c.toStdString());
526 return new Process::ComboBox{choices, current(), objectName(), id, parent};
527 }
528
529 auto getValues() const { return choices(); }
530
531 std::string current() const
532 {
533 if(!m_choices.isEmpty() && ossia::valid_index(m_index, m_choices))
534 {
535 return m_choices[m_index].toStdString();
536 }
537 return {};
538 }
539
540 W_INLINE_PROPERTY_VALUE(int, index, {}, index, setIndex, indexChanged)
541 W_INLINE_PROPERTY_CREF(QStringList, choices, {}, choices, setChoices, choicesChanged)
542};
543
544class SCORE_PLUGIN_JS_EXPORT Toggle : public ControlInlet
545{
546 W_OBJECT(Toggle)
547
548public:
549 using ControlInlet::ControlInlet;
550 virtual ~Toggle() override;
551 bool isEvent() const override { return true; }
552 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
553 {
554 return new Process::Toggle{m_checked, objectName(), id, parent};
555 }
556
557 W_INLINE_PROPERTY_VALUE(bool, checked, {}, checked, setChecked, checkedChanged)
558};
559
560class SCORE_PLUGIN_JS_EXPORT Button : public ControlInlet
561{
562 W_OBJECT(Button)
563
564public:
565 using ControlInlet::ControlInlet;
566 virtual ~Button() override;
567 bool isEvent() const override { return true; }
568 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
569 {
570 return new Process::Button{objectName(), id, parent};
571 }
572
573 W_INLINE_PROPERTY_VALUE(bool, checked, {}, checked, setChecked, checkedChanged)
574};
575
576class SCORE_PLUGIN_JS_EXPORT Impulse : public ControlInlet
577{
578 W_OBJECT(Impulse)
579
580public:
581 using ControlInlet::ControlInlet;
582 virtual ~Impulse() override;
583 bool isEvent() const override { return false; }
584 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
585 {
586 return new Process::ImpulseButton{objectName(), id, parent};
587 }
588
589 void impulse() W_SIGNAL(impulse);
590};
591
592class SCORE_PLUGIN_JS_EXPORT LineEdit : public ControlInlet
593{
594 W_OBJECT(LineEdit)
595
596public:
597 using ControlInlet::ControlInlet;
598 virtual ~LineEdit() override;
599 bool isEvent() const override { return true; }
600 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
601 {
602 return new Process::LineEdit{m_text, objectName(), id, parent};
603 }
604
605 W_INLINE_PROPERTY_CREF(QString, text, {}, text, setText, textChanged)
606};
607
608class SCORE_PLUGIN_JS_EXPORT HSVSlider
609 : public GenericControlInlet<Process::HSVSlider, QColor, ossia::vec4f>
610{
611 W_OBJECT(HSVSlider)
612
613public:
615 Process::HSVSlider, QColor, ossia::vec4f>::GenericControlInlet;
616 virtual ~HSVSlider() override;
617 bool isEvent() const override { return true; }
618 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
619 {
620 auto col = init().toRgb();
621 ossia::vec4f v{
622 (float)col.redF(), (float)col.greenF(), (float)col.blueF(), (float)col.alphaF()};
623 return new Process::HSVSlider{v, objectName(), id, parent};
624 }
625
626 void setValue(QVariant value) override
627 {
628 auto vec = value.value<QVector4D>();
629 auto conv = QColor::fromRgbF(vec[0], vec[1], vec[2], vec[3]);
630 if(m_value == conv)
631 return;
632
633 m_value = std::move(conv);
634 valueChanged(m_value);
635 }
636 W_INLINE_PROPERTY_CREF(QColor, init, {}, init, setInit, initChanged)
637};
638class SCORE_PLUGIN_JS_EXPORT ValueOutlet : public Outlet
639{
640 W_OBJECT(ValueOutlet)
641
642 QJSValue m_value;
643
644public:
645 std::vector<OutValueMessage> values;
646
647 explicit ValueOutlet(QObject* parent = nullptr);
648 virtual ~ValueOutlet() override;
649 const QJSValue& value() const;
650 void clear()
651 {
652 m_value = QJSValue{};
653 values.clear();
654 }
655 Process::Outlet* make(Id<Process::Port>&& id, QObject* parent) override
656 {
657 return new Process::ValueOutlet(objectName(), id, parent);
658 }
659
660public:
661 void setValue(const QJSValue& value);
662 W_SLOT(setValue);
663 void addValue(qreal timestamp, QJSValue t);
664 W_SLOT(addValue);
665
666 W_PROPERTY(QJSValue, value READ value WRITE setValue)
667};
668
669class SCORE_PLUGIN_JS_EXPORT AudioInlet : public Inlet
670{
671 W_OBJECT(AudioInlet)
672
673public:
674 explicit AudioInlet(QObject* parent = nullptr);
675 virtual ~AudioInlet() override;
676 QVector<QVector<double>>& audio();
677 const QVector<QVector<double>>& audio() const;
678 void setAudio(const QVector<QVector<double>>& audio);
679 void setAudio(QVector<QVector<double>>&& audio);
680
681 QVector<double> channel(int i) const
682 {
683 if(m_audio.size() > i)
684 return m_audio[i];
685 return {};
686 }
687 W_INVOKABLE(channel);
688
689 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
690 {
691 return new Process::AudioInlet(objectName(), id, parent);
692 }
693
694private:
695 QVector<QVector<double>> m_audio;
696};
697
698class SCORE_PLUGIN_JS_EXPORT AudioOutlet : public Outlet
699{
700 W_OBJECT(AudioOutlet)
701
702public:
703 explicit AudioOutlet(QObject* parent = nullptr);
704 virtual ~AudioOutlet() override;
705 Process::Outlet* make(Id<Process::Port>&& id, QObject* parent) override
706 {
707 auto p = new Process::AudioOutlet(objectName(), id, parent);
708 if(id.val() == 0)
709 p->setPropagate(true);
710 return p;
711 }
712
713 const QVector<QVector<double>>& audio() const;
714
715 void setChannel(int i, const QJSValue& v);
716 W_INVOKABLE(setChannel)
717
718 void clear() { m_audio.clear(); }
719
720private:
721 QVector<QVector<double>> m_audio;
722};
723
724class SCORE_PLUGIN_JS_EXPORT MidiMessage
725{
726 W_GADGET(MidiMessage)
727
728public:
729 QByteArray bytes;
730
731 W_PROPERTY(QByteArray, bytes MEMBER bytes)
732};
733
734class SCORE_PLUGIN_JS_EXPORT MidiInlet : public Inlet
735{
736 W_OBJECT(MidiInlet)
737
738public:
739 explicit MidiInlet(QObject* parent = nullptr);
740 virtual ~MidiInlet() override;
741 template <typename T>
742 void setMidi(const T& arr)
743 {
744 m_midi.clear();
745 for(const libremidi::ump& mess : arr)
746 {
747 const auto m1 = libremidi::midi1_from_ump(mess);
748 if(m1.bytes.empty())
749 continue;
750
751 QVector<int> m;
752 m.resize(m1.bytes.size());
753 for(std::size_t i = 0; i < m1.bytes.size(); i++)
754 m[i] = m1.bytes[i];
755
756 m_midi.push_back(QVariant::fromValue(m));
757 }
758 }
759
760 QVariantList messages() const { return m_midi; }
761 W_INVOKABLE(messages);
762
763 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
764 {
765 return new Process::MidiInlet(objectName(), id, parent);
766 }
767
768private:
769 QVariantList m_midi;
770};
771
772class SCORE_PLUGIN_JS_EXPORT MidiOutlet : public Outlet
773{
774 W_OBJECT(MidiOutlet)
775
776public:
777 explicit MidiOutlet(QObject* parent = nullptr);
778 virtual ~MidiOutlet() override;
779 Process::Outlet* make(Id<Process::Port>&& id, QObject* parent) override
780 {
781 return new Process::MidiOutlet(objectName(), id, parent);
782 }
783
784 void clear();
785 const QVector<QVector<int>>& midi() const;
786
787 void setMessages(const QVariantList m)
788 {
789 m_midi.clear();
790 for(auto& v : m)
791 {
792 if(v.canConvert<QVector<int>>())
793 m_midi.push_back(v.value<QVector<int>>());
794 }
795 }
796 W_INVOKABLE(setMessages);
797
798 void add(QVector<int> m) { m_midi.push_back(std::move(m)); }
799 W_INVOKABLE(add);
800
801private:
802 QVector<QVector<int>> m_midi;
803};
804
805#if defined(SCORE_HAS_GPU_JS)
806class TextureInlet : public Inlet
807{
808 W_OBJECT(TextureInlet)
809
810public:
811 explicit TextureInlet(QObject* parent = nullptr);
812 virtual ~TextureInlet() override;
813 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
814 {
815 auto p = new Gfx::TextureInlet(objectName(), id, parent);
816 return p;
817 }
818
819 QQuickItem* item() const noexcept { return m_item; }
820
821 W_PROPERTY(QQuickItem*, item READ item CONSTANT)
822private:
823 QQuickItem* m_item{};
824};
825
826class TextureOutlet : public Outlet
827{
828 W_OBJECT(TextureOutlet)
829
830public:
831 explicit TextureOutlet(QObject* parent = nullptr);
832 virtual ~TextureOutlet() override;
833 Process::Outlet* make(Id<Process::Port>&& id, QObject* parent) override
834 {
835 auto p = new Gfx::TextureOutlet(objectName(), id, parent);
836 return p;
837 }
838
839 QQuickItem* item() const noexcept { return m_item; }
840 void setItem(QQuickItem* v) { m_item = v; }
841
842 W_PROPERTY(QQuickItem*, item READ item WRITE setItem CONSTANT)
843private:
844 QQuickItem* m_item{};
845};
846#endif
847
848class SCORE_PLUGIN_JS_EXPORT Script : public QObject
849{
850 W_OBJECT(Script)
851 W_CLASSINFO("DefaultProperty", "data")
852
853public:
854 QQmlListProperty<QObject> data() noexcept { return {this, &m_data}; }
855 W_PROPERTY(QQmlListProperty<QObject>, data READ data)
856
857 const QJSValue& tick() const noexcept { return m_tick; }
858 void setTick(const QJSValue& v) { m_tick = v; }
859 W_PROPERTY(QJSValue, tick READ tick WRITE setTick CONSTANT)
860
861 const QJSValue& start() const noexcept { return m_start; }
862 void setStart(const QJSValue& v) { m_start = v; }
863 W_PROPERTY(QJSValue, start READ start WRITE setStart CONSTANT)
864
865 const QJSValue& stop() const noexcept { return m_stop; }
866 void setStop(const QJSValue& v) { m_stop = v; }
867 W_PROPERTY(QJSValue, stop READ stop WRITE setStop CONSTANT)
868
869 const QJSValue& pause() const noexcept { return m_pause; }
870 void setPause(const QJSValue& v) { m_pause = v; }
871 W_PROPERTY(QJSValue, pause READ pause WRITE setPause CONSTANT)
872
873 const QJSValue& resume() const noexcept { return m_resume; }
874 void setResume(const QJSValue& v) { m_resume = v; }
875 W_PROPERTY(QJSValue, resume READ resume WRITE setResume CONSTANT)
876
877 const QJSValue& uiEvent() const noexcept { return m_uiEvent; }
878 void setUiEvent(const QJSValue& v) { m_uiEvent = v; }
879 W_PROPERTY(QJSValue, uiEvent READ uiEvent WRITE setUiEvent CONSTANT)
880
881 void uiSend(const QJSValue& v) W_SIGNAL(uiSend, v);
882
883 // Persist execution-originated edits through the document command stack,
884 // including when no ScriptUI is open. The value is queued to the GUI thread.
885 void commitState(const QString& key, const QJSValue& value)
886 W_SIGNAL(commitState, key, value);
887
888 const QJSValue& loadState() const noexcept { return m_loadState; }
889 void setLoadState(const QJSValue& v) { m_loadState = v; }
890 W_PROPERTY(QJSValue, loadState READ loadState WRITE setLoadState CONSTANT)
891
892 const QJSValue& stateUpdated() const noexcept { return m_stateUpdated; }
893 void setStateUpdated(const QJSValue& v) { m_stateUpdated = v; }
894 W_PROPERTY(QJSValue, stateUpdated READ stateUpdated WRITE setStateUpdated CONSTANT)
895
896private:
897 QList<QObject*> m_data;
898 QJSValue m_tick;
899 QJSValue m_start;
900 QJSValue m_stop;
901 QJSValue m_pause;
902 QJSValue m_resume;
903 QJSValue m_uiEvent;
904 QJSValue m_loadState;
905 QJSValue m_stateUpdated;
906};
907
908class ScriptUI : public QQuickItem
909{
910 W_OBJECT(ScriptUI)
911
912public:
913 const QJSValue& executionEvent() const noexcept { return m_executionEvent; }
914 void setExecutionEvent(const QJSValue& v) { m_executionEvent = v; }
915 W_PROPERTY(QJSValue, executionEvent READ executionEvent WRITE setExecutionEvent CONSTANT)
916
917 const QJSValue& loadState() const noexcept { return m_loadState; }
918 void setLoadState(const QJSValue& v) { m_loadState = v; }
919 W_PROPERTY(QJSValue, loadState READ loadState WRITE setLoadState CONSTANT)
920
921 const QJSValue& stateUpdated() const noexcept { return m_stateUpdated; }
922 void setStateUpdated(const QJSValue& v) { m_stateUpdated = v; }
923 W_PROPERTY(QJSValue, stateUpdated READ stateUpdated WRITE setStateUpdated CONSTANT)
924
925 void executionSend(const QJSValue& v)
926 W_SIGNAL(executionSend, v);
927
928 void beginUpdateState(const QString& name)
929 W_SIGNAL(beginUpdateState, name);
930 void updateState(const QString& k, const QJSValue& v)
931 W_SIGNAL(updateState, k, v);
932 void endUpdateState()
933 W_SIGNAL(endUpdateState);
934 void cancelUpdateState()
935 W_SIGNAL(cancelUpdateState);
936 void clearState()
937 W_SIGNAL(clearState);
938 void replaceState(const QJSValue& v)
939 W_SIGNAL(replaceState, v);
940
941 Process::Inlet* inlet(int i) const noexcept;
942 W_INVOKABLE(inlet, (int));
943 Process::Outlet* outlet(int i) const noexcept;
944 W_INVOKABLE(outlet, (int));
945 Process::Inlet* inlet(const QString& i) const noexcept;
946 W_INVOKABLE(inlet, (const QString&));
947 Process::Outlet* outlet(const QString& i) const noexcept;
948 W_INVOKABLE(outlet, (const QString&));
949
950 Process::ProcessModel* process() const noexcept { return m_process; }
951 void setProcess(Process::ProcessModel* v) { m_process = v; }
952
953private:
954 QJSValue m_executionEvent;
955 QJSValue m_loadState;
956 QJSValue m_stateUpdated;
957 Process::ProcessModel* m_process{};
958};
959}
960
961inline QDataStream& operator<<(QDataStream& i, const JS::MidiMessage& sel)
962{
963 SCORE_ABORT;
964 return i;
965}
966inline QDataStream& operator>>(QDataStream& i, JS::MidiMessage& sel)
967{
968 SCORE_ABORT;
969 return i;
970}
971inline QDataStream& operator<<(QDataStream& i, const JS::InValueMessage& sel)
972{
973 SCORE_ABORT;
974 return i;
975}
976inline QDataStream& operator>>(QDataStream& i, JS::InValueMessage& sel)
977{
978 SCORE_ABORT;
979 return i;
980}
981inline QDataStream& operator<<(QDataStream& i, const JS::OutValueMessage& sel)
982{
983 SCORE_ABORT;
984 return i;
985}
986inline QDataStream& operator>>(QDataStream& i, JS::OutValueMessage& sel)
987{
988 SCORE_ABORT;
989 return i;
990}
991Q_DECLARE_METATYPE(JS::ValueInlet*)
992Q_DECLARE_METATYPE(JS::ValueOutlet*)
993Q_DECLARE_METATYPE(JS::AudioInlet*)
994Q_DECLARE_METATYPE(JS::AudioOutlet*)
995Q_DECLARE_METATYPE(JS::MidiMessage)
996Q_DECLARE_METATYPE(JS::MidiInlet*)
997Q_DECLARE_METATYPE(JS::MidiOutlet*)
998
999W_REGISTER_ARGTYPE(JS::ValueInlet*)
1000W_REGISTER_ARGTYPE(JS::ValueOutlet*)
1001W_REGISTER_ARGTYPE(JS::AudioInlet*)
1002W_REGISTER_ARGTYPE(JS::AudioOutlet*)
1003W_REGISTER_ARGTYPE(JS::MidiMessage)
1004W_REGISTER_ARGTYPE(JS::MidiInlet*)
1005W_REGISTER_ARGTYPE(JS::MidiOutlet*)
Definition QmlObjects.hpp:670
Definition QmlObjects.hpp:699
Definition QmlObjects.hpp:561
Definition QmlObjects.hpp:512
Definition QmlObjects.hpp:123
Definition QmlObjects.hpp:483
Definition QmlObjects.hpp:357
Definition QmlObjects.hpp:284
Definition QmlObjects.hpp:379
Definition QmlObjects.hpp:452
Definition QmlObjects.hpp:215
Definition QmlObjects.hpp:147
Definition QmlObjects.hpp:610
Definition QmlObjects.hpp:577
Definition QmlObjects.hpp:43
Definition QmlObjects.hpp:328
Definition QmlObjects.hpp:423
Definition QmlObjects.hpp:237
Definition QmlObjects.hpp:593
Definition QmlObjects.hpp:735
Definition QmlObjects.hpp:725
Definition QmlObjects.hpp:773
Definition QmlObjects.hpp:56
Definition QmlObjects.hpp:849
Definition QmlObjects.hpp:909
Definition QmlObjects.hpp:545
Definition QmlObjects.hpp:90
Definition QmlObjects.hpp:639
Definition Port.hpp:327
Definition Port.hpp:350
Definition Port.hpp:218
Definition Port.hpp:192
Definition Port.hpp:406
Definition Port.hpp:429
Definition Port.hpp:300
The Process class.
Definition score-lib-process/Process/Process.hpp:75
Definition Port.hpp:518
Definition Port.hpp:544
The id_base_t class.
Definition Identifier.hpp:59
Base classes and tools to implement processes and layers.
Definition JSONVisitor.hpp:1115
STL namespace.
Definition QmlObjects.hpp:202
Definition QmlObjects.hpp:196
Definition QmlObjects.hpp:68
Definition QmlObjects.hpp:190
Definition QmlObjects.hpp:79
Definition QmlObjects.hpp:208
Definition WidgetInlets.hpp:536
Definition WidgetInlets.hpp:467
Definition WidgetInlets.hpp:512
Definition WidgetInlets.hpp:560
Definition WidgetInlets.hpp:547
Definition WidgetInlets.hpp:351
Definition WidgetInlets.hpp:326