85 SCORE_SERIALIZE_FRIENDS
88 friend struct
TSerializer<JSONObject, oscr::ProcessModel<Info>>;
92 oscr::dynamic_ports_storage<Info> dynamic_ports;
95 ossia::type_if<Info, oscr::has_dynamic_ports<Info>> object_storage_for_ports_callbacks;
98 const TimeVal& duration, const Id<Process::ProcessModel>& id,
99 const score::DocumentContext& ctx, QObject* parent)
103 metadata().setInstanceName(*
this);
106 init_before_port_creation();
108 init_after_port_creation();
112 const TimeVal& duration,
const QString& custom,
117 metadata().setInstanceName(*
this);
120 init_before_port_creation();
123 if constexpr(avnd::file_input_introspection<Info>::size > 0)
125 static constexpr auto idx
126 = avnd::file_input_introspection<Info>::index_to_field_index(0);
127 setupInitialStringPort(idx, custom);
129 else if constexpr(avnd::control_input_introspection<Info>::size > 0)
131 static constexpr auto idx
132 = avnd::control_input_introspection<Info>::index_to_field_index(0);
134 typename avnd::control_input_introspection<Info>::template nth_element<0>;
135 if constexpr(avnd::string_ish<
decltype(type::value)>)
136 setupInitialStringPort(idx, custom);
138 init_after_port_creation();
141 void setupInitialStringPort(
int idx,
const QString& custom)
noexcept
144 auto pp = safe_cast<Process::ControlInlet*>(port);
146 if(
auto val = pp->value(); bool(val.target<std::string>()))
148 pp->setValue(custom.toStdString());
152 template <
typename Impl>
157 init_before_port_creation();
160 init_after_port_creation();
168 if constexpr(avnd::tag_loops_by_default<Info>)
172 void init_before_port_creation() { init_dynamic_ports(); }
173 void init_after_port_creation() { init_controller_ports(); }
174 void check_all_ports()
176 if(std::ssize(m_inlets) != expected_input_ports()
177 || std::ssize(m_outlets) != expected_output_ports())
179 qDebug() <<
typeid(Info).name() << this->metadata().getName()
180 <<
": WARNING : process does not match spec: I " << m_inlets.size()
181 <<
"but expected: " << expected_input_ports() <<
" ; O "
182 << m_outlets.size() <<
"but expected: " << expected_output_ports();
184 std::vector<Dataflow::SavedPort> m_oldInlets, m_oldOutlets;
185 for(
auto& port : m_inlets)
186 m_oldInlets.emplace_back(
188 for(
auto& port : m_outlets)
189 m_oldOutlets.emplace_back(
192 qDeleteAll(m_inlets);
194 qDeleteAll(m_outlets);
199 Dataflow::reloadPortsInNewProcess(m_oldInlets, m_oldOutlets, *
this);
203 void init_controller_ports()
206 avnd::dynamic_ports_input_introspection<Info>::size > 0
207 || avnd::dynamic_ports_output_introspection<Info>::size > 0)
209 avnd::control_input_introspection<Info>::for_all_n2(
210 avnd::get_inputs<Info>((Info&)this->object_storage_for_ports_callbacks),
211 [
this]<std::size_t Idx,
typename F>(
212 F& field,
auto pred_index, avnd::field_index<Idx>) {
213 Info& obj = this->object_storage_for_ports_callbacks;
214 if constexpr(
requires { F::on_controller_setup(); })
216 auto controller_inlets = avnd_input_idx_to_model_ports(Idx);
217 SCORE_ASSERT(controller_inlets.size() == 1);
218 auto inlet = qobject_cast<Process::ControlInlet*>(controller_inlets[0]);
220 oscr::from_ossia_value(inlet->value(), field.value);
222 if_possible(field.update(obj));
224 F::on_controller_setup()(obj, field.value);
226 if constexpr(
requires { F::on_controller_interaction(); })
228 auto controller_inlets = avnd_input_idx_to_model_ports(Idx);
229 SCORE_ASSERT(controller_inlets.size() == 1);
230 auto inlet = qobject_cast<Process::ControlInlet*>(controller_inlets[0]);
231 inlet->noValueChangeOnMove =
true;
233 if constexpr(!
requires { F::on_controller_setup(); })
235 oscr::from_ossia_value(inlet->value(), field.value);
236 if_possible(field.update(obj));
237 F::on_controller_interaction()(obj, field.value);
241 inlet, &Process::ControlInlet::valueChanged,
242 [
this, &field](
const ossia::value& val) {
243 Info& obj = this->object_storage_for_ports_callbacks;
244 oscr::from_ossia_value(val, field.value);
246 if_possible(field.update(obj));
248 F::on_controller_interaction()(obj, field.value);
253 if constexpr(avnd::has_gui_to_processor_bus<Info>)
258 if constexpr(avnd::has_processor_to_gui_bus<Info>)
260 Info& obj = this->object_storage_for_ports_callbacks;
262 obj.send_message = [
this]<
typename T>(T&& b)
mutable {
264 MessageBusSender{this->to_ui}(std::move(b));
270 void init_dynamic_ports()
306 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size > 0)
308 Info& obj = object_storage_for_ports_callbacks;
309 avnd::dynamic_ports_input_introspection<Info>::for_all_n2(
310 avnd::get_inputs(obj),
311 [&]<std::size_t N>(
auto& port,
auto pred_idx, avnd::field_index<N> field_idx) {
312 port.request_port_resize = [
this, &port](
int new_count) {
318 if(score::IDocument::documentFromObject(*this)->loaded())
320 QTimer::singleShot(0,
this, [self = QPointer{
this}, &port, new_count] {
322 self->request_new_dynamic_input_count(
323 port, avnd::field_index<N>{}, new_count);
328 this->request_new_dynamic_input_count(
329 port, avnd::field_index<N>{}, new_count);
335 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size > 0)
337 Info& obj = object_storage_for_ports_callbacks;
338 avnd::dynamic_ports_output_introspection<Info>::for_all_n2(
339 avnd::get_outputs(obj),
340 [&]<std::size_t N>(
auto& port,
auto pred_idx, avnd::field_index<N> field_idx) {
341 port.request_port_resize = [
this, &port](
int new_count) {
343 if(score::IDocument::documentFromObject(*this)->loaded())
345 QTimer::singleShot(0,
this, [self = QPointer{
this}, &port, new_count] {
347 self->request_new_dynamic_output_count(
348 port, avnd::field_index<N>{}, new_count);
353 this->request_new_dynamic_output_count(
354 port, avnd::field_index<N>{}, new_count);
361 template <
typename P, std::
size_t N>
362 void request_new_dynamic_input_count(P& port, avnd::field_index<N> idx,
int count)
364 const int current_model_ports = dynamic_ports.num_in_ports(idx);
365 if(current_model_ports == count || count < 0 || count > 512)
368 ossia::small_pod_vector<Process::Inlet*, 4> to_delete;
369 if(current_model_ports < count)
373 auto res = avnd_input_idx_to_iterator(idx);
374 res += current_model_ports;
376 InletInitFunc<Info> inlets{*
this, inlets_to_add};
377 inlets.inlet = 10000 + N * 1000 + current_model_ports;
379 for(
int i = current_model_ports; i < count; i++)
382 if(std::ssize(inlets_to_add) > sz)
384 sz = std::ssize(inlets_to_add);
385 auto new_inlet = inlets_to_add.back();
386 if(
auto nm = new_inlet->name(); nm.contains(
"{}"))
388 nm.replace(
"{}", QString::number(i));
389 new_inlet->setName(nm);
393 m_inlets.insert(res, inlets_to_add.begin(), inlets_to_add.end());
395 else if(current_model_ports > count)
398 auto res = avnd_input_idx_to_iterator(idx);
400 auto begin_deleted = res;
401 for(
int i = 0; i < (current_model_ports - count); i++)
403 to_delete.push_back(*res);
406 m_inlets.erase(begin_deleted, res);
409 dynamic_ports.num_in_ports(idx) = count;
412 for(
auto port : to_delete)
416 template <
typename P, std::
size_t N>
417 void request_new_dynamic_output_count(P& port, avnd::field_index<N> idx,
int count)
419 const int current_model_ports = dynamic_ports.num_out_ports(idx);
420 if(current_model_ports == count || count < 0 || count > 512)
423 ossia::small_pod_vector<Process::Outlet*, 4> to_delete;
424 if(current_model_ports < count)
428 auto res = avnd_output_idx_to_iterator(idx);
429 res += current_model_ports;
431 OutletInitFunc<Info> outlets{*
this, outlets_to_add};
432 outlets.outlet = 1000000 + N * 1000 + current_model_ports;
434 for(
int i = current_model_ports; i < count; i++)
437 if(std::ssize(outlets_to_add) > sz)
439 sz = std::ssize(outlets_to_add);
440 auto new_outlet = outlets_to_add.back();
441 if(
auto nm = new_outlet->name(); nm.contains(
"{}"))
443 nm.replace(
"{}", QString::number(i));
444 new_outlet->setName(nm);
448 m_outlets.insert(res, outlets_to_add.begin(), outlets_to_add.end());
450 else if(current_model_ports > count)
453 auto res = avnd_output_idx_to_iterator(idx);
455 auto begin_deleted = res;
456 for(
int i = 0; i < (current_model_ports - count); i++)
458 to_delete.push_back(*res);
461 m_outlets.erase(begin_deleted, res);
464 dynamic_ports.num_out_ports(idx) = count;
467 for(
auto port : to_delete)
471 void init_all_ports()
473 InletInitFunc<Info> inlets{*
this, m_inlets};
474 OutletInitFunc<Info> outlets{*
this, m_outlets};
475 avnd::port_visit_dispatcher<Info>([&inlets]<
typename P>(P&& port,
auto idx) {
476 if constexpr(!avnd::dynamic_ports_port<P>)
478 }, [&outlets]<
typename P>(P&& port,
auto idx) {
479 if constexpr(!avnd::dynamic_ports_port<P>)
483 if(!
requires { Info::ossia_show_ports_by_default; })
485 hideAllInlets(*
this);
489 int expected_input_ports() const noexcept
495 if constexpr(avnd::audio_argument_processor<Info>)
497 else if constexpr(avnd::tag_cv<Info>)
501 count += avnd::messages_introspection<Info>::size;
503 avnd::input_introspection<Info>::for_all([
this, &count]<std::size_t Idx,
typename P>(
504 avnd::field_reflection<Idx, P> field) {
506 if constexpr(avnd::dynamic_ports_port<P>)
507 num_ports = dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
514 int expected_output_ports() const noexcept
520 if constexpr(avnd::audio_argument_processor<Info>)
522 else if constexpr(avnd::tag_cv<Info>)
524 using operator_ret =
typename avnd::function_reflection_o<Info>::return_type;
525 if constexpr(!std::is_void_v<operator_ret>)
529 avnd::output_introspection<Info>::for_all(
531 &count]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
533 if constexpr(avnd::dynamic_ports_port<P>)
534 num_ports = dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
541 std::span<Process::Inlet*> avnd_input_idx_to_model_ports(
int index)
const noexcept
547 if constexpr(avnd::audio_argument_processor<Info>)
549 else if constexpr(avnd::tag_cv<Info>)
553 model_index += avnd::messages_introspection<Info>::size;
555 std::span<Process::Inlet*> ret;
556 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size == 0)
558 ret = std::span<Process::Inlet*>(
559 const_cast<Process::Inlet**
>(this->m_inlets.data()) + model_index + index, 1);
563 avnd::input_introspection<Info>::for_all(
564 [
this, index, &model_index,
565 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
569 if constexpr(avnd::dynamic_ports_port<P>)
571 num_ports = dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
578 ret = std::span<Process::Inlet*>(
579 const_cast<Process::Inlet**
>(this->m_inlets.data()) + model_index,
584 if constexpr(avnd::dynamic_ports_port<P>)
586 model_index += dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
599 std::span<Process::Outlet*> avnd_output_idx_to_model_ports(
int index)
const noexcept
605 if constexpr(avnd::audio_argument_processor<Info>)
607 else if constexpr(avnd::tag_cv<Info>)
609 using operator_ret =
typename avnd::function_reflection_o<Info>::return_type;
610 if constexpr(!std::is_void_v<operator_ret>)
615 model_index += avnd::messages_introspection<Info>::size;
617 std::span<Process::Outlet*> ret;
618 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size == 0)
620 ret = std::span<Process::Outlet*>(
621 const_cast<Process::Outlet**
>(this->m_outlets.data()) + model_index + index,
626 avnd::output_introspection<Info>::for_all(
627 [
this, index, &model_index,
628 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
632 if constexpr(avnd::dynamic_ports_port<P>)
634 num_ports = dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
641 ret = std::span<Process::Outlet*>(
647 if constexpr(avnd::dynamic_ports_port<P>)
649 model_index += dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
662 Process::Inlets::iterator avnd_input_idx_to_iterator(
int index)
const noexcept
668 if constexpr(avnd::audio_argument_processor<Info>)
672 model_index += avnd::messages_introspection<Info>::size;
674 Process::Inlets::iterator ret;
675 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size == 0)
677 ret =
const_cast<ProcessModel*
>(
this)->m_inlets.begin() + model_index;
681 avnd::input_introspection<Info>::for_all(
682 [
this, index, &model_index,
683 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
686 ret =
const_cast<ProcessModel*
>(
this)->m_inlets.begin() + model_index;
690 if constexpr(avnd::dynamic_ports_port<P>)
692 model_index += dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
704 Process::Outlets::iterator avnd_output_idx_to_iterator(
int index)
const noexcept
710 if constexpr(avnd::audio_argument_processor<Info>)
714 model_index += avnd::messages_introspection<Info>::size;
716 Process::Outlets::iterator ret;
717 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size == 0)
719 ret =
const_cast<ProcessModel*
>(
this)->m_outlets.begin() + model_index;
723 avnd::output_introspection<Info>::for_all(
724 [
this, index, &model_index,
725 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
728 ret =
const_cast<ProcessModel*
>(
this)->m_outlets.begin() + model_index;
732 if constexpr(avnd::dynamic_ports_port<P>)
734 model_index += dynamic_ports.num_out_ports(avnd::field_index<Idx>{});