87 SCORE_SERIALIZE_FRIENDS
90 friend struct
TSerializer<JSONObject, oscr::ProcessModel<Info>>;
94 oscr::dynamic_ports_storage<Info> dynamic_ports;
97 ossia::type_if<Info, oscr::has_dynamic_ports<Info>> object_storage_for_ports_callbacks;
100 const TimeVal& duration, const Id<Process::ProcessModel>& id,
101 const score::DocumentContext& ctx, QObject* parent)
105 metadata().setInstanceName(*
this);
108 init_before_port_creation();
110 init_after_port_creation();
114 const TimeVal& duration,
const QString& custom,
119 metadata().setInstanceName(*
this);
122 init_before_port_creation();
125 if constexpr(avnd::file_input_introspection<Info>::size > 0)
127 static constexpr auto idx
128 = avnd::file_input_introspection<Info>::index_to_field_index(0);
129 setupInitialStringPort(idx, custom);
131 else if constexpr(avnd::control_input_introspection<Info>::size > 0)
133 static constexpr auto idx
134 = avnd::control_input_introspection<Info>::index_to_field_index(0);
136 typename avnd::control_input_introspection<Info>::template nth_element<0>;
137 if constexpr(avnd::string_ish<
decltype(type::value)>)
138 setupInitialStringPort(idx, custom);
140 init_after_port_creation();
143 void setupInitialStringPort(
int idx,
const QString& custom)
noexcept
146 auto pp = safe_cast<Process::ControlInlet*>(port);
148 if(
auto val = pp->value(); bool(val.target<std::string>()))
150 pp->setValue(custom.toStdString());
154 template <
typename Impl>
159 init_before_port_creation();
162 init_after_port_creation();
170 if constexpr(avnd::tag_loops_by_default<Info>)
174 void init_before_port_creation() { init_dynamic_ports(); }
175 void init_after_port_creation() { init_controller_ports(); }
176 void check_all_ports()
178 if(std::ssize(m_inlets) != expected_input_ports()
179 || std::ssize(m_outlets) != expected_output_ports())
181 qDebug() <<
typeid(Info).name() << this->metadata().getName()
182 <<
": WARNING : process does not match spec: I " << m_inlets.size()
183 <<
"but expected: " << expected_input_ports() <<
" ; O "
184 << m_outlets.size() <<
"but expected: " << expected_output_ports();
186 std::vector<Dataflow::SavedPort> m_oldInlets, m_oldOutlets;
187 for(
auto& port : m_inlets)
188 m_oldInlets.emplace_back(
190 for(
auto& port : m_outlets)
191 m_oldOutlets.emplace_back(
194 qDeleteAll(m_inlets);
196 qDeleteAll(m_outlets);
201 Dataflow::reloadPortsInNewProcess(m_oldInlets, m_oldOutlets, *
this);
205 void init_controller_ports()
208 avnd::dynamic_ports_input_introspection<Info>::size > 0
209 || avnd::dynamic_ports_output_introspection<Info>::size > 0)
211 avnd::control_input_introspection<Info>::for_all_n2(
212 avnd::get_inputs<Info>((Info&)this->object_storage_for_ports_callbacks),
213 [
this]<std::size_t Idx,
typename F>(
214 F& field,
auto pred_index, avnd::field_index<Idx>) {
215 Info& obj = this->object_storage_for_ports_callbacks;
216 if constexpr(
requires { F::on_controller_setup(); })
218 auto controller_inlets = avnd_input_idx_to_model_ports(Idx);
219 SCORE_ASSERT(controller_inlets.size() == 1);
220 auto inlet = qobject_cast<Process::ControlInlet*>(controller_inlets[0]);
222 oscr::from_ossia_value(inlet->value(), field.value);
224 if_possible(field.update(obj));
226 F::on_controller_setup()(obj, field.value);
228 if constexpr(
requires { F::on_controller_interaction(); })
230 auto controller_inlets = avnd_input_idx_to_model_ports(Idx);
231 SCORE_ASSERT(controller_inlets.size() == 1);
232 auto inlet = qobject_cast<Process::ControlInlet*>(controller_inlets[0]);
233 inlet->noValueChangeOnMove =
true;
235 if constexpr(!
requires { F::on_controller_setup(); })
237 oscr::from_ossia_value(inlet->value(), field.value);
238 if_possible(field.update(obj));
239 F::on_controller_interaction()(obj, field.value);
243 inlet, &Process::ControlInlet::valueChanged,
244 [
this, &field](
const ossia::value& val) {
245 Info& obj = this->object_storage_for_ports_callbacks;
246 oscr::from_ossia_value(val, field.value);
248 if_possible(field.update(obj));
250 F::on_controller_interaction()(obj, field.value);
255 if constexpr(avnd::has_gui_to_processor_bus<Info>)
260 if constexpr(avnd::has_processor_to_gui_bus<Info>)
262 Info& obj = this->object_storage_for_ports_callbacks;
264 obj.send_message = [
this]<
typename T>(T&& b)
mutable {
266 MessageBusSender{this->to_ui}(std::move(b));
272 void init_dynamic_ports()
308 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size > 0)
310 Info& obj = object_storage_for_ports_callbacks;
311 avnd::dynamic_ports_input_introspection<Info>::for_all_n2(
312 avnd::get_inputs(obj),
313 [&]<std::size_t N>(
auto& port,
auto pred_idx, avnd::field_index<N> field_idx) {
314 port.request_port_resize = [
this, &port](
int new_count) {
320 if(score::IDocument::documentFromObject(*this)->loaded())
322 QTimer::singleShot(0,
this, [self = QPointer{
this}, &port, new_count] {
324 self->request_new_dynamic_input_count(
325 port, avnd::field_index<N>{}, new_count);
330 this->request_new_dynamic_input_count(
331 port, avnd::field_index<N>{}, new_count);
337 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size > 0)
339 Info& obj = object_storage_for_ports_callbacks;
340 avnd::dynamic_ports_output_introspection<Info>::for_all_n2(
341 avnd::get_outputs(obj),
342 [&]<std::size_t N>(
auto& port,
auto pred_idx, avnd::field_index<N> field_idx) {
343 port.request_port_resize = [
this, &port](
int new_count) {
345 if(score::IDocument::documentFromObject(*this)->loaded())
347 QTimer::singleShot(0,
this, [self = QPointer{
this}, &port, new_count] {
349 self->request_new_dynamic_output_count(
350 port, avnd::field_index<N>{}, new_count);
355 this->request_new_dynamic_output_count(
356 port, avnd::field_index<N>{}, new_count);
363 template <
typename P, std::
size_t N>
364 void request_new_dynamic_input_count(P& port, avnd::field_index<N> idx,
int count)
366 const int current_model_ports = dynamic_ports.num_in_ports(idx);
367 if(current_model_ports == count || count < 0 || count > 512)
370 ossia::small_pod_vector<Process::Inlet*, 4> to_delete;
371 if(current_model_ports < count)
375 auto res = avnd_input_idx_to_iterator(idx);
376 res += current_model_ports;
378 InletInitFunc<Info> inlets{*
this, inlets_to_add};
379 inlets.inlet = 10000 + N * 1000 + current_model_ports;
381 for(
int i = current_model_ports; i < count; i++)
384 if(std::ssize(inlets_to_add) > sz)
386 sz = std::ssize(inlets_to_add);
387 auto new_inlet = inlets_to_add.back();
388 if(
auto nm = new_inlet->name(); nm.contains(
"{}"))
390 nm.replace(
"{}", QString::number(i));
391 new_inlet->setName(nm);
395 m_inlets.insert(res, inlets_to_add.begin(), inlets_to_add.end());
397 else if(current_model_ports > count)
400 auto res = avnd_input_idx_to_iterator(idx);
402 auto begin_deleted = res;
403 for(
int i = 0; i < (current_model_ports - count); i++)
405 to_delete.push_back(*res);
408 m_inlets.erase(begin_deleted, res);
411 dynamic_ports.num_in_ports(idx) = count;
414 for(
auto port : to_delete)
418 template <
typename P, std::
size_t N>
419 void request_new_dynamic_output_count(P& port, avnd::field_index<N> idx,
int count)
421 const int current_model_ports = dynamic_ports.num_out_ports(idx);
422 if(current_model_ports == count || count < 0 || count > 512)
425 ossia::small_pod_vector<Process::Outlet*, 4> to_delete;
426 if(current_model_ports < count)
430 auto res = avnd_output_idx_to_iterator(idx);
431 res += current_model_ports;
433 OutletInitFunc<Info> outlets{*
this, outlets_to_add};
434 outlets.outlet = 1000000 + N * 1000 + current_model_ports;
436 for(
int i = current_model_ports; i < count; i++)
439 if(std::ssize(outlets_to_add) > sz)
441 sz = std::ssize(outlets_to_add);
442 auto new_outlet = outlets_to_add.back();
443 if(
auto nm = new_outlet->name(); nm.contains(
"{}"))
445 nm.replace(
"{}", QString::number(i));
446 new_outlet->setName(nm);
450 m_outlets.insert(res, outlets_to_add.begin(), outlets_to_add.end());
452 else if(current_model_ports > count)
455 auto res = avnd_output_idx_to_iterator(idx);
457 auto begin_deleted = res;
458 for(
int i = 0; i < (current_model_ports - count); i++)
460 to_delete.push_back(*res);
463 m_outlets.erase(begin_deleted, res);
466 dynamic_ports.num_out_ports(idx) = count;
469 for(
auto port : to_delete)
473 void init_all_ports()
475 InletInitFunc<Info> inlets{*
this, m_inlets};
476 OutletInitFunc<Info> outlets{*
this, m_outlets};
477 avnd::port_visit_dispatcher<Info>([&inlets]<
typename P>(P&& port,
auto idx) {
478 if constexpr(!avnd::dynamic_ports_port<P>)
480 }, [&outlets]<
typename P>(P&& port,
auto idx) {
481 if constexpr(!avnd::dynamic_ports_port<P>)
485 if(!
requires { Info::ossia_show_ports_by_default; })
487 hideAllInlets(*
this);
491 int expected_input_ports() const noexcept
497 if constexpr(avnd::audio_argument_processor<Info>)
499 else if constexpr(avnd::tag_cv<Info>)
503 count += avnd::messages_introspection<Info>::size;
505 avnd::input_introspection<Info>::for_all([
this, &count]<std::size_t Idx,
typename P>(
506 avnd::field_reflection<Idx, P> field) {
508 if constexpr(avnd::dynamic_ports_port<P>)
509 num_ports = dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
516 int expected_output_ports() const noexcept
522 if constexpr(avnd::audio_argument_processor<Info>)
524 else if constexpr(avnd::tag_cv<Info>)
526 using operator_ret =
typename avnd::function_reflection_o<Info>::return_type;
527 if constexpr(!std::is_void_v<operator_ret>)
531 avnd::output_introspection<Info>::for_all(
533 &count]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
535 if constexpr(avnd::dynamic_ports_port<P>)
536 num_ports = dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
543 std::span<Process::Inlet*> avnd_input_idx_to_model_ports(
int index)
const noexcept
549 if constexpr(avnd::audio_argument_processor<Info>)
551 else if constexpr(avnd::tag_cv<Info>)
555 model_index += avnd::messages_introspection<Info>::size;
557 std::span<Process::Inlet*> ret;
558 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size == 0)
560 ret = std::span<Process::Inlet*>(
561 const_cast<Process::Inlet**
>(this->m_inlets.data()) + model_index + index, 1);
565 avnd::input_introspection<Info>::for_all(
566 [
this, index, &model_index,
567 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
571 if constexpr(avnd::dynamic_ports_port<P>)
573 num_ports = dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
580 ret = std::span<Process::Inlet*>(
581 const_cast<Process::Inlet**
>(this->m_inlets.data()) + model_index,
586 if constexpr(avnd::dynamic_ports_port<P>)
588 model_index += dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
601 std::span<Process::Outlet*> avnd_output_idx_to_model_ports(
int index)
const noexcept
607 if constexpr(avnd::audio_argument_processor<Info>)
609 else if constexpr(avnd::tag_cv<Info>)
611 using operator_ret =
typename avnd::function_reflection_o<Info>::return_type;
612 if constexpr(!std::is_void_v<operator_ret>)
617 model_index += avnd::messages_introspection<Info>::size;
619 std::span<Process::Outlet*> ret;
620 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size == 0)
622 ret = std::span<Process::Outlet*>(
623 const_cast<Process::Outlet**
>(this->m_outlets.data()) + model_index + index,
628 avnd::output_introspection<Info>::for_all(
629 [
this, index, &model_index,
630 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
634 if constexpr(avnd::dynamic_ports_port<P>)
636 num_ports = dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
643 ret = std::span<Process::Outlet*>(
649 if constexpr(avnd::dynamic_ports_port<P>)
651 model_index += dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
664 Process::Inlets::iterator avnd_input_idx_to_iterator(
int index)
const noexcept
670 if constexpr(avnd::audio_argument_processor<Info>)
674 model_index += avnd::messages_introspection<Info>::size;
676 Process::Inlets::iterator ret;
677 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size == 0)
679 ret =
const_cast<ProcessModel*
>(
this)->m_inlets.begin() + model_index;
683 avnd::input_introspection<Info>::for_all(
684 [
this, index, &model_index,
685 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
688 ret =
const_cast<ProcessModel*
>(
this)->m_inlets.begin() + model_index;
692 if constexpr(avnd::dynamic_ports_port<P>)
694 model_index += dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
706 Process::Outlets::iterator avnd_output_idx_to_iterator(
int index)
const noexcept
712 if constexpr(avnd::audio_argument_processor<Info>)
716 model_index += avnd::messages_introspection<Info>::size;
718 Process::Outlets::iterator ret;
719 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size == 0)
721 ret =
const_cast<ProcessModel*
>(
this)->m_outlets.begin() + model_index;
725 avnd::output_introspection<Info>::for_all(
726 [
this, index, &model_index,
727 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
730 ret =
const_cast<ProcessModel*
>(
this)->m_outlets.begin() + model_index;
734 if constexpr(avnd::dynamic_ports_port<P>)
736 model_index += dynamic_ports.num_out_ports(avnd::field_index<Idx>{});