Loading...
Searching...
No Matches
ProcessModelPortInit.hpp
1#pragma once
2#include <Process/Dataflow/Port.hpp>
3#include <Process/Dataflow/PortFactory.hpp>
4#include <Process/Process.hpp>
5
6#include <Crousti/Concepts.hpp>
7#include <Crousti/SceneConcepts.hpp>
8#include <Media/Sound/Drop/SoundDrop.hpp>
9
10#include <avnd/binding/ossia/port_base.hpp>
11#include <avnd/concepts/all.hpp>
12#if SCORE_PLUGIN_GFX
13#include <Gfx/TexturePort.hpp>
14#endif
15
16namespace oscr
17{
18template <typename Info>
19class ProcessModel;
20}
21
22namespace oscr
23{
24
25template <typename T>
26static AVND_INLINE QString portName()
27{
28 //FIXME
29#if !defined(__APPLE__)
30 static constexpr auto name = avnd::get_name<T>();
31 return fromStringView(name);
32#else
33 auto name = avnd::get_name<T>();
34 return fromStringView(name);
35#endif
36}
37
38template <typename T>
39inline void setupNewPort(Process::Port* obj)
40{
41 if constexpr(avnd::has_description<T>)
42 obj->setDescription(fromStringView(avnd::get_description<T>()));
43 static_assert(
44 !single_cable_port<T> || avnd::gpu_texture_port<T> || avnd::buffer_port<T>
45 || avnd::geometry_port<T> || scene_port<T>,
46 "single_cable is only supported on GPU texture, buffer, geometry and scene "
47 "inputs");
48 if constexpr(single_cable_port<T>)
49 obj->singleCable = true;
50}
51
52template <std::size_t N, typename T>
53inline void setupNewPort(const avnd::field_reflection<N, T>& spec, Process::Port* obj)
54{
55 setupNewPort<T>(obj);
56}
57
58template <typename T>
59inline void setupNewPort(const T& spec, Process::Port* obj)
60{
61 setupNewPort<T>(obj);
62}
63
64template <typename Node>
66{
68 Process::Inlets& ins;
69 int inlet = 0;
70
71 template <oscr::ossia_value_port T>
72 void operator()(const T& in, auto idx)
73 {
74 auto p = new Process::ValueInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
75 setupNewPort(in, p);
76 ins.push_back(p);
77 }
78 template <oscr::ossia_audio_port T>
79 void operator()(const T& in, auto idx)
80 {
81 auto p = new Process::AudioInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
82 setupNewPort(in, p);
83 ins.push_back(p);
84 }
85 template <oscr::ossia_midi_port T>
86 void operator()(const T& in, auto idx)
87 {
88 auto p = new Process::MidiInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
89 setupNewPort(in, p);
90 ins.push_back(p);
91 }
92
93 template <avnd::audio_port T>
94 void operator()(const T& in, auto idx)
95 {
96 auto p = new Process::AudioInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
97 setupNewPort(in, p);
98 ins.push_back(p);
99 }
100 template <avnd::midi_port T>
101 void operator()(const T& in, auto idx)
102 {
103 auto p = new Process::MidiInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
104 setupNewPort(in, p);
105 ins.push_back(p);
106 }
107
108 static QString toFilters(const QSet<QString>& exts)
109 {
110 QString res;
111 for(const auto& s : exts)
112 {
113 res += "*.";
114 res += s;
115 res += " ";
116 }
117 if(!res.isEmpty())
118 res.resize(res.size() - 1);
119 return res;
120 }
121
122 template <typename P>
123 static QString getFilters(P& p)
124 {
125 if constexpr(requires { P::filters(); })
126 {
127 using filter = decltype(P::filters());
128 if constexpr(requires { filter::sound; } || requires { filter::audio; })
129 {
130 return QString{"Sound files (%1)"}.arg(
131 toFilters(Media::Sound::DropHandler{}.fileExtensions()));
132 }
133 else if constexpr(requires { filter::video; })
134 {
135 // FIXME refactor supported formats with Video process
136 QSet<QString> files = {"mkv", "mov", "mp4", "h264", "avi", "hap", "mpg", "mpeg",
137 "imf", "mxf", "mts", "m2ts", "mj2", "webm", "y4m", "nut", "ts"};
138 return QString{"Videos (%1)"}.arg(toFilters(files));
139 }
140 else if constexpr(requires { filter::image; })
141 {
142 // FIXME refactor supported formats with Image List Chooser
143 return QString{"Images (*.png *.jpg *.jpeg *.gif *.bmp *.tiff)"};
144 }
145 else if constexpr(requires { filter::midi; })
146 {
147 return "MIDI (*.mid)";
148 }
149 else if constexpr(avnd::string_ish<filter>)
150 {
151 static constexpr auto text_filters = P::filters();
152 return fromStringView(P::filters());
153 }
154 else
155 {
156 return "";
157 }
158 }
159 else if constexpr(requires { P::extensions(); })
160 {
161 static constexpr auto text_filters = P::extensions();
162 return fromStringView(text_filters);
163 }
164 else
165 {
166 return "";
167 }
168 }
169
170 template <avnd::soundfile_port T>
171 void operator()(const T& in, auto idx)
172 {
173 static constexpr auto name = avnd::get_name<T>();
174 Process::FileChooserBase* p{};
175 if constexpr(requires { T::waveform; })
176 {
177 p = new Process::AudioFileChooser{
178 "", getFilters(in), QString::fromUtf8(name.data(), name.size()),
179 Id<Process::Port>(inlet++), &self};
180 }
181 else
182 {
183 p = new Process::FileChooser{
184 "", getFilters(in), QString::fromUtf8(name.data(), name.size()),
185 Id<Process::Port>(inlet++), &self};
186 }
187
188 p->displayHandledExplicitly = true;
189 ins.push_back(p);
190
191 if constexpr(avnd::tag_file_watch<T>)
192 {
193 p->enableFileWatch();
194 }
195 }
196
197 template <typename T>
198 requires avnd::midifile_port<T> || avnd::raw_file_port<T>
199 void operator()(const T& in, auto idx)
200 {
201 static constexpr auto name = avnd::get_name<T>();
202
203 auto p = new Process::FileChooser{
204 "", getFilters(in), QString::fromUtf8(name.data(), name.size()),
205 Id<Process::Port>(inlet++), &self};
206 p->displayHandledExplicitly = true;
207 ins.push_back(p);
208
209 if constexpr(avnd::tag_file_watch<T>)
210 {
211 p->enableFileWatch();
212 }
213 }
214
215 template <avnd::dynamic_ports_port T, std::size_t N>
216 void operator()(const T& in, avnd::field_index<N> i)
217 {
218 using port_type = typename decltype(in.ports)::value_type;
219 port_type p;
220 (*this)(p, i);
221 }
222
223 template <avnd::parameter_port T, std::size_t N>
224 requires(!oscr::ossia_port<T>)
225 void operator()(const T& in, avnd::field_index<N>)
226 {
227 if constexpr(avnd::has_widget<T> || avnd::curve_port<T>)
228 {
229 auto p = oscr::make_control_in<Node, T>(
230 avnd::field_index<N>{}, Id<Process::Port>(inlet), &self);
231 using port_ptr_type = std::decay_t<decltype(p)>;
232 if constexpr(!std::is_same_v<port_ptr_type, std::nullptr_t>)
233 {
234 if constexpr(
235 !std::is_same_v<port_ptr_type, Process::ControlInlet*>
236 && !std::is_same_v<port_ptr_type, Process::ValueInlet*>)
237 p->displayHandledExplicitly = true;
238
239 setupNewPort(in, p);
240 ins.push_back(p);
241 }
242 else
243 {
244 auto vp
245 = new Process::ValueInlet(portName<T>(), Id<Process::Port>(inlet), &self);
246 setupNewPort(in, vp);
247 ins.push_back(vp);
248 }
249 }
250 else
251 {
252 auto vp = new Process::ValueInlet(portName<T>(), Id<Process::Port>(inlet), &self);
253 setupNewPort(in, vp);
254 ins.push_back(vp);
255 }
256 inlet++;
257 }
258
259 template <avnd::buffer_port T>
260 void operator()(const T& in, auto idx)
261 {
262#if SCORE_PLUGIN_GFX
263 auto p = new Gfx::TextureInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
264 setupNewPort(in, p);
265 ins.push_back(p);
266#endif
267 }
268
269 template <avnd::texture_port T>
270 void operator()(const T& in, auto idx)
271 {
272#if SCORE_PLUGIN_GFX
273 auto p = new Gfx::TextureInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
274 setupNewPort(in, p);
275 ins.push_back(p);
276#endif
277 }
278
279 template <avnd::geometry_port T>
280 void operator()(const T& in, auto idx)
281 {
282#if SCORE_PLUGIN_GFX
283 auto p = new Gfx::GeometryInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
284 setupNewPort(in, p);
285 ins.push_back(p);
286#endif
287 }
288
289 // Scene inputs reuse Gfx::GeometryInlet — a scene is a richer form of
290 // geometry and travels through the same Process-layer port. Mirror of the
291 // outlet overload below. Needed so scene-modifying halp nodes (Transform,
292 // SceneFilter, ...) can declare `struct { ossia::scene_spec scene; } scene_in;`
293 // in their inputs{} struct and get wired up by the framework.
294 template <scene_port T>
295 requires(!avnd::geometry_port<T>)
296 void operator()(const T& in, auto idx)
297 {
298#if SCORE_PLUGIN_GFX
299 auto p = new Gfx::GeometryInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
300 setupNewPort(in, p);
301 ins.push_back(p);
302#endif
303 }
304
305 template <std::size_t Idx, avnd::message T>
306 void operator()(const avnd::field_reflection<Idx, T>& in, auto dummy)
307 {
308 auto p = new Process::ValueInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
309 setupNewPort(in, p);
310 ins.push_back(p);
311 }
312
313 template <std::size_t Idx, avnd::unreflectable_message<Node> T>
314 void operator()(const avnd::field_reflection<Idx, T>& in, auto dummy)
315 {
316 auto p = new Process::ValueInlet(portName<T>(), Id<Process::Port>(inlet++), &self);
317 setupNewPort(in, p);
318 ins.push_back(p);
319 }
320
321 void operator()(const auto& ctrl, auto idx)
322 {
323 //(avnd::message<std::decay_t<decltype(ctrl)>>);
324 qDebug() << fromStringView(avnd::get_name(ctrl)) << "unhandled";
325 }
326};
327
328template <typename Node>
330{
332 Process::Outlets& outs;
333 int outlet = 0;
334
335 template <oscr::ossia_value_port T>
336 void operator()(const T& out, auto idx)
337 {
338 auto p = new Process::ValueOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
339 setupNewPort(out, p);
340 outs.push_back(p);
341 }
342
343 template <oscr::ossia_audio_port T>
344 void operator()(const T& out, auto idx)
345 {
346 auto p = new Process::AudioOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
347 setupNewPort(out, p);
348 outs.push_back(p);
349 }
350
351 template <oscr::ossia_midi_port T>
352 void operator()(const T& out, auto idx)
353 {
354 auto p = new Process::MidiOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
355 setupNewPort(out, p);
356 outs.push_back(p);
357 }
358
359 template <avnd::dynamic_ports_port T, std::size_t N>
360 void operator()(const T& in, avnd::field_index<N> i)
361 {
362 using port_type = typename decltype(in.ports)::value_type;
363 port_type p;
364 (*this)(p, i);
365 }
366
367 template <avnd::audio_port T>
368 void operator()(const T& out, auto idx)
369 {
370 auto p = new Process::AudioOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
371 setupNewPort(out, p);
372 if(outlet == 1)
373 p->setPropagate(true);
374 outs.push_back(p);
375 }
376
377 template <avnd::midi_port T>
378 void operator()(const T& out, auto idx)
379 {
380 auto p = new Process::MidiOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
381 setupNewPort(out, p);
382 outs.push_back(p);
383 }
384
385 template <avnd::parameter_port T, std::size_t N>
386 requires(!oscr::ossia_port<T>)
387 void operator()(const T& out, avnd::field_index<N>)
388 {
389 if constexpr(avnd::has_widget<T>)
390 {
391 if(auto p = oscr::make_control_out<T>(
392 avnd::field_index<N>{}, Id<Process::Port>(outlet), &self))
393 {
394 p->displayHandledExplicitly = true;
395 setupNewPort(out, p);
396 outs.push_back(p);
397 }
398 else
399 {
400 // FIXME ControlOutlet?
401 auto vp
402 = new Process::ValueOutlet(portName<T>(), Id<Process::Port>(outlet), &self);
403 setupNewPort(out, vp);
404 outs.push_back(vp);
405 }
406 }
407 else
408 {
409 auto vp
410 = new Process::ValueOutlet(portName<T>(), Id<Process::Port>(outlet), &self);
411 setupNewPort(out, vp);
412 outs.push_back(vp);
413 }
414 outlet++;
415 }
416
417 template <avnd::buffer_port T>
418 void operator()(const T& out, auto idx)
419 {
420#if SCORE_PLUGIN_GFX
421 auto p = new Gfx::TextureOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
422 setupNewPort(out, p);
423 outs.push_back(p);
424#endif
425 }
426
427 template <avnd::texture_port T>
428 void operator()(const T& out, auto idx)
429 {
430#if SCORE_PLUGIN_GFX
431 auto p = new Gfx::TextureOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
432 setupNewPort(out, p);
433 outs.push_back(p);
434#endif
435 }
436
437 template <avnd::gpu_render_target_output_port T>
438 void operator()(const T& out, auto idx)
439 {
440#if SCORE_PLUGIN_GFX
441 auto p = new Gfx::TextureOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
442 setupNewPort(out, p);
443 outs.push_back(p);
444#endif
445 }
446
447 template <avnd::geometry_port T>
448 void operator()(const T& out, auto idx)
449 {
450#if SCORE_PLUGIN_GFX
451 auto p = new Gfx::GeometryOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
452 setupNewPort(out, p);
453 outs.push_back(p);
454#endif
455 }
456
457 // Scene outputs reuse Gfx::GeometryOutlet — a scene is a richer form of
458 // geometry that travels through the same Process-layer port. The Crousti
459 // upload path publishes scene_spec via NodeRenderer::process(scene_spec).
460 template <scene_port T>
461 requires(!avnd::geometry_port<T>)
462 void operator()(const T& out, auto idx)
463 {
464#if SCORE_PLUGIN_GFX
465 auto p = new Gfx::GeometryOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
466 setupNewPort(out, p);
467 outs.push_back(p);
468#endif
469 }
470
471 template <avnd::curve_port T>
472 void operator()(const T& out, auto idx)
473 {
474 auto p = new Process::ValueOutlet(portName<T>(), Id<Process::Port>(outlet++), &self);
475 setupNewPort(out, p);
476 outs.push_back(p);
477 }
478
479 template <avnd::callback T, std::size_t N>
480 void operator()(const T& out, avnd::field_index<N>)
481 {
482 if constexpr(avnd::control_port<T>)
483 {
484 if(auto p = oscr::make_control_out<T>(
485 avnd::field_index<N>{}, Id<Process::Port>(outlet), &self))
486 {
487 p->hidden = true;
488 outs.push_back(p);
489 }
490 else
491 {
492 // FIXME ControlOutlet?
493 auto vp
494 = new Process::ValueOutlet(portName<T>(), Id<Process::Port>(outlet), &self);
495 setupNewPort(out, vp);
496 outs.push_back(vp);
497 }
498 }
499 else if constexpr(requires { T::control; })
500 {
501 // FIXME remove this duplication
502 auto p
503 = new Process::ControlOutlet(portName<T>(), Id<Process::Port>(outlet), &self);
504 setupNewPort(out, p);
505 outs.push_back(p);
506 }
507 else
508 {
509 auto p = new Process::ValueOutlet(portName<T>(), Id<Process::Port>(outlet), &self);
510 setupNewPort(out, p);
511 outs.push_back(p);
512 }
513 outlet++;
514 }
515
516 void operator()(const auto& ctrl, auto idx)
517 {
518 qDebug() << fromStringView(avnd::get_name(ctrl)) << "unhandled";
519 }
520};
521}
Definition TexturePort.hpp:168
Definition TexturePort.hpp:191
The DropHandler class If something with audio mime type is dropped, then we create a box with an audi...
Definition SoundDrop.hpp:26
Definition Port.hpp:356
Definition Port.hpp:379
Definition Port.hpp:481
Definition Port.hpp:435
Definition Port.hpp:458
Definition Port.hpp:106
The Process class.
Definition score-lib-process/Process/Process.hpp:82
Definition Port.hpp:547
Definition Port.hpp:573
The id_base_t class.
Definition Identifier.hpp:59
Definition Controls.hpp:30
Definition PortForward.hpp:23
Definition PortForward.hpp:27
Definition ProcessModelPortInit.hpp:66
Definition ProcessModelPortInit.hpp:330