80 SCORE_SERIALIZE_FRIENDS
83 friend struct
TSerializer<JSONObject, oscr::ProcessModel<Info>>;
87 oscr::dynamic_ports_storage<Info> dynamic_ports;
90 ossia::type_if<Info, oscr::has_dynamic_ports<Info>> object_storage_for_ports_callbacks;
93 const TimeVal& duration, const Id<Process::ProcessModel>& id,
94 const score::DocumentContext& ctx, QObject* parent)
98 metadata().setInstanceName(*
this);
101 init_before_port_creation();
103 init_after_port_creation();
107 const TimeVal& duration,
const QString& custom,
112 metadata().setInstanceName(*
this);
115 init_before_port_creation();
118 if constexpr(avnd::file_input_introspection<Info>::size > 0)
120 static constexpr auto idx
121 = avnd::file_input_introspection<Info>::index_to_field_index(0);
122 setupInitialStringPort(idx, custom);
124 else if constexpr(avnd::control_input_introspection<Info>::size > 0)
126 static constexpr auto idx
127 = avnd::control_input_introspection<Info>::index_to_field_index(0);
129 typename avnd::control_input_introspection<Info>::template nth_element<0>;
130 if constexpr(avnd::string_ish<
decltype(type::value)>)
131 setupInitialStringPort(idx, custom);
133 init_after_port_creation();
136 void setupInitialStringPort(
int idx,
const QString& custom)
noexcept
139 auto pp = safe_cast<Process::ControlInlet*>(port);
141 if(
auto val = pp->value(); bool(val.target<std::string>()))
143 pp->setValue(custom.toStdString());
147 template <
typename Impl>
152 init_before_port_creation();
155 init_after_port_creation();
163 if constexpr(avnd::tag_loops_by_default<Info>)
167 void init_before_port_creation() { init_dynamic_ports(); }
168 void init_after_port_creation() { init_controller_ports(); }
169 void check_all_ports()
171 if(std::ssize(m_inlets) != expected_input_ports()
172 || std::ssize(m_outlets) != expected_output_ports())
174 qDebug() <<
"Warning : process does not match spec: I " << m_inlets.size()
175 <<
"but expected: " << expected_input_ports() <<
" ; O "
176 << m_outlets.size() <<
"but expected: " << expected_output_ports();
178 std::vector<Dataflow::SavedPort> m_oldInlets, m_oldOutlets;
179 for(
auto& port : m_inlets)
180 m_oldInlets.emplace_back(
182 for(
auto& port : m_outlets)
183 m_oldOutlets.emplace_back(
186 qDeleteAll(m_inlets);
188 qDeleteAll(m_outlets);
193 Dataflow::reloadPortsInNewProcess(m_oldInlets, m_oldOutlets, *
this);
197 void init_controller_ports()
200 avnd::dynamic_ports_input_introspection<Info>::size > 0
201 || avnd::dynamic_ports_output_introspection<Info>::size > 0)
203 avnd::control_input_introspection<Info>::for_all_n2(
204 avnd::get_inputs<Info>((Info&)this->object_storage_for_ports_callbacks),
205 [
this]<std::size_t Idx,
typename F>(
206 F& field,
auto pred_index, avnd::field_index<Idx>) {
207 Info& obj = this->object_storage_for_ports_callbacks;
208 if constexpr(
requires { F::on_controller_setup(); })
210 auto controller_inlets = avnd_input_idx_to_model_ports(Idx);
211 SCORE_ASSERT(controller_inlets.size() == 1);
212 auto inlet = qobject_cast<Process::ControlInlet*>(controller_inlets[0]);
214 oscr::from_ossia_value(inlet->value(), field.value);
216 if_possible(field.update(obj));
218 F::on_controller_setup()(obj, field.value);
220 if constexpr(
requires { F::on_controller_interaction(); })
222 auto controller_inlets = avnd_input_idx_to_model_ports(Idx);
223 SCORE_ASSERT(controller_inlets.size() == 1);
224 auto inlet = qobject_cast<Process::ControlInlet*>(controller_inlets[0]);
225 inlet->noValueChangeOnMove =
true;
227 inlet, &Process::ControlInlet::valueChanged,
228 [
this, &field](
const ossia::value& val) {
229 Info& obj = this->object_storage_for_ports_callbacks;
230 oscr::from_ossia_value(val, field.value);
232 if_possible(field.update(obj));
234 F::on_controller_interaction()(obj, field.value);
239 if constexpr(avnd::has_gui_to_processor_bus<Info>)
244 if constexpr(avnd::has_processor_to_gui_bus<Info>)
246 Info& obj = this->object_storage_for_ports_callbacks;
248 obj.send_message = [
this]<
typename T>(T&& b)
mutable {
250 MessageBusSender{this->to_ui}(std::move(b));
256 void init_dynamic_ports()
292 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size > 0)
294 Info& obj = object_storage_for_ports_callbacks;
295 avnd::dynamic_ports_input_introspection<Info>::for_all_n2(
296 avnd::get_inputs(obj),
297 [&]<std::size_t N>(
auto& port,
auto pred_idx, avnd::field_index<N> field_idx) {
298 port.request_port_resize = [
this, &port](
int new_count) {
304 if(score::IDocument::documentFromObject(*this)->loaded())
306 QTimer::singleShot(0,
this, [self = QPointer{
this}, &port, new_count] {
308 self->request_new_dynamic_input_count(
309 port, avnd::field_index<N>{}, new_count);
314 this->request_new_dynamic_input_count(
315 port, avnd::field_index<N>{}, new_count);
321 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size > 0)
323 Info& obj = object_storage_for_ports_callbacks;
324 avnd::dynamic_ports_output_introspection<Info>::for_all_n2(
325 avnd::get_outputs(obj),
326 [&]<std::size_t N>(
auto& port,
auto pred_idx, avnd::field_index<N> field_idx) {
327 port.request_port_resize = [
this, &port](
int new_count) {
329 if(score::IDocument::documentFromObject(*this)->loaded())
331 QTimer::singleShot(0,
this, [self = QPointer{
this}, &port, new_count] {
333 self->request_new_dynamic_output_count(
334 port, avnd::field_index<N>{}, new_count);
339 this->request_new_dynamic_output_count(
340 port, avnd::field_index<N>{}, new_count);
347 template <
typename P, std::
size_t N>
348 void request_new_dynamic_input_count(P& port, avnd::field_index<N> idx,
int count)
350 const int current_model_ports = dynamic_ports.num_in_ports(idx);
351 if(current_model_ports == count || count < 0 || count > 512)
354 ossia::small_pod_vector<Process::Inlet*, 4> to_delete;
355 if(current_model_ports < count)
359 auto res = avnd_input_idx_to_iterator(idx);
360 res += current_model_ports;
362 InletInitFunc<Info> inlets{*
this, inlets_to_add};
363 inlets.inlet = 10000 + N * 1000 + current_model_ports;
365 for(
int i = current_model_ports; i < count; i++)
368 if(std::ssize(inlets_to_add) > sz)
370 sz = std::ssize(inlets_to_add);
371 auto new_inlet = inlets_to_add.back();
372 if(
auto nm = new_inlet->name(); nm.contains(
"{}"))
374 nm.replace(
"{}", QString::number(i));
375 new_inlet->setName(nm);
379 m_inlets.insert(res, inlets_to_add.begin(), inlets_to_add.end());
381 else if(current_model_ports > count)
384 auto res = avnd_input_idx_to_iterator(idx);
386 auto begin_deleted = res;
387 for(
int i = 0; i < (current_model_ports - count); i++)
389 to_delete.push_back(*res);
392 m_inlets.erase(begin_deleted, res);
395 dynamic_ports.num_in_ports(idx) = count;
398 for(
auto port : to_delete)
402 template <
typename P, std::
size_t N>
403 void request_new_dynamic_output_count(P& port, avnd::field_index<N> idx,
int count)
405 const int current_model_ports = dynamic_ports.num_out_ports(idx);
406 if(current_model_ports == count || count < 0 || count > 512)
409 ossia::small_pod_vector<Process::Outlet*, 4> to_delete;
410 if(current_model_ports < count)
414 auto res = avnd_output_idx_to_iterator(idx);
415 res += current_model_ports;
417 OutletInitFunc<Info> outlets{*
this, outlets_to_add};
418 outlets.outlet = 1000000 + N * 1000 + current_model_ports;
420 for(
int i = current_model_ports; i < count; i++)
423 if(std::ssize(outlets_to_add) > sz)
425 sz = std::ssize(outlets_to_add);
426 auto new_outlet = outlets_to_add.back();
427 if(
auto nm = new_outlet->name(); nm.contains(
"{}"))
429 nm.replace(
"{}", QString::number(i));
430 new_outlet->setName(nm);
434 m_outlets.insert(res, outlets_to_add.begin(), outlets_to_add.end());
436 else if(current_model_ports > count)
439 auto res = avnd_output_idx_to_iterator(idx);
441 auto begin_deleted = res;
442 for(
int i = 0; i < (current_model_ports - count); i++)
444 to_delete.push_back(*res);
447 m_outlets.erase(begin_deleted, res);
450 dynamic_ports.num_out_ports(idx) = count;
453 for(
auto port : to_delete)
457 void init_all_ports()
459 InletInitFunc<Info> inlets{*
this, m_inlets};
460 OutletInitFunc<Info> outlets{*
this, m_outlets};
461 avnd::port_visit_dispatcher<Info>([&inlets]<
typename P>(P&& port,
auto idx) {
462 if constexpr(!avnd::dynamic_ports_port<P>)
464 }, [&outlets]<
typename P>(P&& port,
auto idx) {
465 if constexpr(!avnd::dynamic_ports_port<P>)
471 int expected_input_ports() const noexcept
477 if constexpr(avnd::audio_argument_processor<Info>)
479 else if constexpr(avnd::tag_cv<Info>)
483 count += avnd::messages_introspection<Info>::size;
485 avnd::input_introspection<Info>::for_all([
this, &count]<std::size_t Idx,
typename P>(
486 avnd::field_reflection<Idx, P> field) {
488 if constexpr(avnd::dynamic_ports_port<P>)
489 num_ports = dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
496 int expected_output_ports() const noexcept
502 if constexpr(avnd::audio_argument_processor<Info>)
504 else if constexpr(avnd::tag_cv<Info>)
506 using operator_ret =
typename avnd::function_reflection_o<Info>::return_type;
507 if constexpr(!std::is_void_v<operator_ret>)
511 avnd::output_introspection<Info>::for_all(
513 &count]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
515 if constexpr(avnd::dynamic_ports_port<P>)
516 num_ports = dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
523 std::span<Process::Inlet*> avnd_input_idx_to_model_ports(
int index)
const noexcept
529 if constexpr(avnd::audio_argument_processor<Info>)
531 else if constexpr(avnd::tag_cv<Info>)
535 model_index += avnd::messages_introspection<Info>::size;
537 std::span<Process::Inlet*> ret;
538 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size == 0)
540 ret = std::span<Process::Inlet*>(
541 const_cast<Process::Inlet**
>(this->m_inlets.data()) + model_index + index, 1);
545 avnd::input_introspection<Info>::for_all(
546 [
this, index, &model_index,
547 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
551 if constexpr(avnd::dynamic_ports_port<P>)
553 num_ports = dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
560 ret = std::span<Process::Inlet*>(
561 const_cast<Process::Inlet**
>(this->m_inlets.data()) + model_index,
566 if constexpr(avnd::dynamic_ports_port<P>)
568 model_index += dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
581 std::span<Process::Outlet*> avnd_output_idx_to_model_ports(
int index)
const noexcept
587 if constexpr(avnd::audio_argument_processor<Info>)
589 else if constexpr(avnd::tag_cv<Info>)
591 using operator_ret =
typename avnd::function_reflection_o<Info>::return_type;
592 if constexpr(!std::is_void_v<operator_ret>)
597 model_index += avnd::messages_introspection<Info>::size;
599 std::span<Process::Outlet*> ret;
600 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size == 0)
602 ret = std::span<Process::Outlet*>(
603 const_cast<Process::Outlet**
>(this->m_outlets.data()) + model_index + index,
608 avnd::output_introspection<Info>::for_all(
609 [
this, index, &model_index,
610 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
614 if constexpr(avnd::dynamic_ports_port<P>)
616 num_ports = dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
623 ret = std::span<Process::Outlet*>(
629 if constexpr(avnd::dynamic_ports_port<P>)
631 model_index += dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
644 Process::Inlets::iterator avnd_input_idx_to_iterator(
int index)
const noexcept
650 if constexpr(avnd::audio_argument_processor<Info>)
654 model_index += avnd::messages_introspection<Info>::size;
656 Process::Inlets::iterator ret;
657 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size == 0)
659 ret =
const_cast<ProcessModel*
>(
this)->m_inlets.begin() + model_index;
663 avnd::input_introspection<Info>::for_all(
664 [
this, index, &model_index,
665 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
668 ret =
const_cast<ProcessModel*
>(
this)->m_inlets.begin() + model_index;
672 if constexpr(avnd::dynamic_ports_port<P>)
674 model_index += dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
686 Process::Outlets::iterator avnd_output_idx_to_iterator(
int index)
const noexcept
692 if constexpr(avnd::audio_argument_processor<Info>)
696 model_index += avnd::messages_introspection<Info>::size;
698 Process::Outlets::iterator ret;
699 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size == 0)
701 ret =
const_cast<ProcessModel*
>(
this)->m_outlets.begin() + model_index;
705 avnd::output_introspection<Info>::for_all(
706 [
this, index, &model_index,
707 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
710 ret =
const_cast<ProcessModel*
>(
this)->m_outlets.begin() + model_index;
714 if constexpr(avnd::dynamic_ports_port<P>)
716 model_index += dynamic_ports.num_out_ports(avnd::field_index<Idx>{});