78 SCORE_SERIALIZE_FRIENDS
81 friend struct
TSerializer<JSONObject, oscr::ProcessModel<Info>>;
85 oscr::dynamic_ports_storage<Info> dynamic_ports;
88 ossia::type_if<Info, oscr::has_dynamic_ports<Info>> object_storage_for_ports_callbacks;
91 const TimeVal& duration, const Id<Process::ProcessModel>& id,
92 const score::DocumentContext& ctx, QObject* parent)
96 metadata().setInstanceName(*
this);
99 init_before_port_creation();
101 init_after_port_creation();
105 const TimeVal& duration,
const QString& custom,
110 metadata().setInstanceName(*
this);
113 init_before_port_creation();
116 if constexpr(avnd::file_input_introspection<Info>::size > 0)
118 static constexpr auto idx
119 = avnd::file_input_introspection<Info>::index_to_field_index(0);
120 setupInitialStringPort(idx, custom);
122 else if constexpr(avnd::control_input_introspection<Info>::size > 0)
124 static constexpr auto idx
125 = avnd::control_input_introspection<Info>::index_to_field_index(0);
127 typename avnd::control_input_introspection<Info>::template nth_element<0>;
128 if constexpr(avnd::string_ish<
decltype(type::value)>)
129 setupInitialStringPort(idx, custom);
131 init_after_port_creation();
134 void setupInitialStringPort(
int idx,
const QString& custom)
noexcept
137 auto pp = safe_cast<Process::ControlInlet*>(port);
139 if(pp->value().target<std::string>())
141 pp->setValue(custom.toStdString());
145 template <
typename Impl>
150 init_before_port_creation();
153 init_after_port_creation();
161 if constexpr(avnd::tag_loops_by_default<Info>)
165 void init_before_port_creation() { init_dynamic_ports(); }
166 void init_after_port_creation() { init_controller_ports(); }
167 void check_all_ports()
169 if(std::ssize(m_inlets) != expected_input_ports()
170 || std::ssize(m_outlets) != expected_output_ports())
172 qDebug() <<
"Warning : process does not match spec: I " << m_inlets.size()
173 <<
"but expected: " << expected_input_ports() <<
" ; O "
174 << m_outlets.size() <<
"but expected: " << expected_output_ports();
176 std::vector<Dataflow::SavedPort> m_oldInlets, m_oldOutlets;
177 for(
auto& port : m_inlets)
178 m_oldInlets.emplace_back(
180 for(
auto& port : m_outlets)
181 m_oldOutlets.emplace_back(
184 qDeleteAll(m_inlets);
186 qDeleteAll(m_outlets);
191 Dataflow::reloadPortsInNewProcess(m_oldInlets, m_oldOutlets, *
this);
195 void init_controller_ports()
198 avnd::dynamic_ports_input_introspection<Info>::size > 0
199 || avnd::dynamic_ports_output_introspection<Info>::size > 0)
201 avnd::control_input_introspection<Info>::for_all_n2(
202 avnd::get_inputs<Info>((Info&)this->object_storage_for_ports_callbacks),
203 [
this]<std::size_t Idx,
typename F>(
204 F& field,
auto pred_index, avnd::field_index<Idx>) {
205 Info& obj = this->object_storage_for_ports_callbacks;
206 if constexpr(
requires { F::on_controller_setup(); })
208 auto controller_inlets = avnd_input_idx_to_model_ports(Idx);
209 SCORE_ASSERT(controller_inlets.size() == 1);
210 auto inlet = qobject_cast<Process::ControlInlet*>(controller_inlets[0]);
212 oscr::from_ossia_value(inlet->value(), field.value);
214 if_possible(field.update(obj));
216 F::on_controller_setup()(obj, field.value);
218 if constexpr(
requires { F::on_controller_interaction(); })
220 auto controller_inlets = avnd_input_idx_to_model_ports(Idx);
221 SCORE_ASSERT(controller_inlets.size() == 1);
222 auto inlet = qobject_cast<Process::ControlInlet*>(controller_inlets[0]);
223 inlet->noValueChangeOnMove =
true;
225 inlet, &Process::ControlInlet::valueChanged,
226 [
this, &field](
const ossia::value& val) {
227 Info& obj = this->object_storage_for_ports_callbacks;
228 oscr::from_ossia_value(val, field.value);
230 if_possible(field.update(obj));
232 F::on_controller_interaction()(obj, field.value);
237 if constexpr(avnd::has_gui_to_processor_bus<Info>)
242 if constexpr(avnd::has_processor_to_gui_bus<Info>)
244 Info& obj = this->object_storage_for_ports_callbacks;
246 obj.send_message = [
this]<
typename T>(T&& b)
mutable {
248 MessageBusSender{this->to_ui}(std::move(b));
254 void init_dynamic_ports()
290 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size > 0)
292 Info& obj = object_storage_for_ports_callbacks;
293 avnd::dynamic_ports_input_introspection<Info>::for_all_n2(
294 avnd::get_inputs(obj),
295 [&]<std::size_t N>(
auto& port,
auto pred_idx, avnd::field_index<N> field_idx) {
296 port.request_port_resize = [
this, &port](
int new_count) {
300 QTimer::singleShot(0,
this, [self = QPointer{
this}, &port, new_count] {
302 self->request_new_dynamic_input_count(
303 port, avnd::field_index<N>{}, new_count);
309 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size > 0)
311 Info& obj = object_storage_for_ports_callbacks;
312 avnd::dynamic_ports_output_introspection<Info>::for_all_n2(
313 avnd::get_outputs(obj),
314 [&]<std::size_t N>(
auto& port,
auto pred_idx, avnd::field_index<N> field_idx) {
315 port.request_port_resize = [
this, &port](
int new_count) {
319 QTimer::singleShot(0,
this, [self = QPointer{
this}, &port, new_count] {
321 self->request_new_dynamic_output_count(
322 port, avnd::field_index<N>{}, new_count);
329 template <
typename P, std::
size_t N>
330 void request_new_dynamic_input_count(P& port, avnd::field_index<N> idx,
int count)
332 const int current_model_ports = dynamic_ports.num_in_ports(idx);
333 if(current_model_ports == count || count < 0 || count > 512)
336 ossia::small_pod_vector<Process::Inlet*, 4> to_delete;
337 if(current_model_ports < count)
341 auto res = avnd_input_idx_to_iterator(idx);
342 res += current_model_ports;
344 InletInitFunc<Info> inlets{*
this, inlets_to_add};
345 inlets.inlet = 10000 + N * 1000 + current_model_ports;
347 for(
int i = current_model_ports; i < count; i++)
350 if(std::ssize(inlets_to_add) > sz)
352 sz = std::ssize(inlets_to_add);
353 auto new_inlet = inlets_to_add.back();
354 if(
auto nm = new_inlet->name(); nm.contains(
"{}"))
356 nm.replace(
"{}", QString::number(i));
357 new_inlet->setName(nm);
361 m_inlets.insert(res, inlets_to_add.begin(), inlets_to_add.end());
363 else if(current_model_ports > count)
366 auto res = avnd_input_idx_to_iterator(idx);
368 auto begin_deleted = res;
369 for(
int i = 0; i < (current_model_ports - count); i++)
371 to_delete.push_back(*res);
374 m_inlets.erase(begin_deleted, res);
377 dynamic_ports.num_in_ports(idx) = count;
380 for(
auto port : to_delete)
384 template <
typename P, std::
size_t N>
385 void request_new_dynamic_output_count(P& port, avnd::field_index<N> idx,
int count)
387 const int current_model_ports = dynamic_ports.num_out_ports(idx);
388 if(current_model_ports == count || count < 0 || count > 512)
391 ossia::small_pod_vector<Process::Outlet*, 4> to_delete;
392 if(current_model_ports < count)
396 auto res = avnd_output_idx_to_iterator(idx);
397 res += current_model_ports;
399 OutletInitFunc<Info> outlets{*
this, outlets_to_add};
400 outlets.outlet = 1000000 + N * 1000 + current_model_ports;
402 for(
int i = current_model_ports; i < count; i++)
405 if(std::ssize(outlets_to_add) > sz)
407 sz = std::ssize(outlets_to_add);
408 auto new_outlet = outlets_to_add.back();
409 if(
auto nm = new_outlet->name(); nm.contains(
"{}"))
411 nm.replace(
"{}", QString::number(i));
412 new_outlet->setName(nm);
416 m_outlets.insert(res, outlets_to_add.begin(), outlets_to_add.end());
418 else if(current_model_ports > count)
421 auto res = avnd_output_idx_to_iterator(idx);
423 auto begin_deleted = res;
424 for(
int i = 0; i < (current_model_ports - count); i++)
426 to_delete.push_back(*res);
429 m_outlets.erase(begin_deleted, res);
432 dynamic_ports.num_out_ports(idx) = count;
435 for(
auto port : to_delete)
439 void init_all_ports()
441 InletInitFunc<Info> inlets{*
this, m_inlets};
442 OutletInitFunc<Info> outlets{*
this, m_outlets};
443 avnd::port_visit_dispatcher<Info>([&inlets]<
typename P>(P&& port,
auto idx) {
444 if constexpr(!avnd::dynamic_ports_port<P>)
446 }, [&outlets]<
typename P>(P&& port,
auto idx) {
447 if constexpr(!avnd::dynamic_ports_port<P>)
453 int expected_input_ports() const noexcept
459 if constexpr(avnd::audio_argument_processor<Info>)
461 else if constexpr(avnd::tag_cv<Info>)
465 count += avnd::messages_introspection<Info>::size;
467 avnd::input_introspection<Info>::for_all([
this, &count]<std::size_t Idx,
typename P>(
468 avnd::field_reflection<Idx, P> field) {
470 if constexpr(avnd::dynamic_ports_port<P>)
471 num_ports = dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
478 int expected_output_ports() const noexcept
484 if constexpr(avnd::audio_argument_processor<Info>)
486 else if constexpr(avnd::tag_cv<Info>)
488 using operator_ret =
typename avnd::function_reflection_o<Info>::return_type;
489 if constexpr(!std::is_void_v<operator_ret>)
493 avnd::output_introspection<Info>::for_all(
495 &count]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
497 if constexpr(avnd::dynamic_ports_port<P>)
498 num_ports = dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
505 std::span<Process::Inlet*> avnd_input_idx_to_model_ports(
int index)
const noexcept
511 if constexpr(avnd::audio_argument_processor<Info>)
513 else if constexpr(avnd::tag_cv<Info>)
517 model_index += avnd::messages_introspection<Info>::size;
519 std::span<Process::Inlet*> ret;
520 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size == 0)
522 ret = std::span<Process::Inlet*>(
523 const_cast<Process::Inlet**
>(this->m_inlets.data()) + model_index + index, 1);
527 avnd::input_introspection<Info>::for_all(
528 [
this, index, &model_index,
529 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
533 if constexpr(avnd::dynamic_ports_port<P>)
535 num_ports = dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
542 ret = std::span<Process::Inlet*>(
543 const_cast<Process::Inlet**
>(this->m_inlets.data()) + model_index,
548 if constexpr(avnd::dynamic_ports_port<P>)
550 model_index += dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
563 std::span<Process::Outlet*> avnd_output_idx_to_model_ports(
int index)
const noexcept
569 if constexpr(avnd::audio_argument_processor<Info>)
571 else if constexpr(avnd::tag_cv<Info>)
573 using operator_ret =
typename avnd::function_reflection_o<Info>::return_type;
574 if constexpr(!std::is_void_v<operator_ret>)
579 model_index += avnd::messages_introspection<Info>::size;
581 std::span<Process::Outlet*> ret;
582 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size == 0)
584 ret = std::span<Process::Outlet*>(
585 const_cast<Process::Outlet**
>(this->m_outlets.data()) + model_index + index,
590 avnd::output_introspection<Info>::for_all(
591 [
this, index, &model_index,
592 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
596 if constexpr(avnd::dynamic_ports_port<P>)
598 num_ports = dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
605 ret = std::span<Process::Outlet*>(
611 if constexpr(avnd::dynamic_ports_port<P>)
613 model_index += dynamic_ports.num_out_ports(avnd::field_index<Idx>{});
626 Process::Inlets::iterator avnd_input_idx_to_iterator(
int index)
const noexcept
632 if constexpr(avnd::audio_argument_processor<Info>)
636 model_index += avnd::messages_introspection<Info>::size;
638 Process::Inlets::iterator ret;
639 if constexpr(avnd::dynamic_ports_input_introspection<Info>::size == 0)
641 ret =
const_cast<ProcessModel*
>(
this)->m_inlets.begin() + model_index;
645 avnd::input_introspection<Info>::for_all(
646 [
this, index, &model_index,
647 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
650 ret =
const_cast<ProcessModel*
>(
this)->m_inlets.begin() + model_index;
654 if constexpr(avnd::dynamic_ports_port<P>)
656 model_index += dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
668 Process::Outlets::iterator avnd_output_idx_to_iterator(
int index)
const noexcept
674 if constexpr(avnd::audio_argument_processor<Info>)
678 model_index += avnd::messages_introspection<Info>::size;
680 Process::Outlets::iterator ret;
681 if constexpr(avnd::dynamic_ports_output_introspection<Info>::size == 0)
683 ret =
const_cast<ProcessModel*
>(
this)->m_outlets.begin() + model_index;
687 avnd::output_introspection<Info>::for_all(
688 [
this, index, &model_index,
689 &ret]<std::size_t Idx,
typename P>(avnd::field_reflection<Idx, P> field) {
692 ret =
const_cast<ProcessModel*
>(
this)->m_outlets.begin() + model_index;
696 if constexpr(avnd::dynamic_ports_port<P>)
698 model_index += dynamic_ports.num_out_ports(avnd::field_index<Idx>{});