2#include <Process/Process.hpp>
4#include <Crousti/File.hpp>
5#include <Crousti/ProcessModel.hpp>
7#include <ossia/detail/flat_map.hpp>
9#include <avnd/binding/ossia/node.hpp>
22template <oscr::has_dynamic_ports T>
27 ossia::flat_map<Process::Inlet*, std::pair<int, QMetaObject::Connection>>
37 { t.value } -> std::convertible_to<std::string_view>;
40template <
typename Node,
typename Field, std::
size_t NPred, std::
size_t NField>
43 using ExecNode = safe_node<Node>;
45 std::weak_ptr<ExecNode> weak_node;
53 static constexpr std::size_t control_index
54 = avnd::control_input_introspection<Node>::field_index_to_index(
55 avnd::field_index<NField>{});
57 void operator()(
const ossia::value& val)
59 using control_value_type = std::decay_t<
decltype(Field::value)>;
61 if(
auto node = weak_node.lock())
64 node->from_ossia_value(field, val, v, avnd::field_index<NField>{});
65 ctx.executionQueue.enqueue([weak_node = weak_node, v = std::move(v)]()
mutable {
66 if(
auto n = weak_node.lock())
68 n->template control_updated_from_ui<control_value_type, control_index>(
79template <
typename Node,
typename Field, std::
size_t NPred, std::
size_t NField>
82 using ExecNode = safe_node<Node>;
84 std::weak_ptr<ExecNode> weak_node;
87 void operator()(
const ossia::value& val)
89 using control_type = avnd::dynamic_port_type<Field>;
90 using control_value_type = std::decay_t<
decltype(control_type::value)>;
92 if(
auto node = weak_node.lock())
99 control_type witness{};
100 control_value_type v;
101 node->from_ossia_value(witness, val, v, avnd::field_index<NField>{});
102 ctx.executionQueue.enqueue([weak_node = weak_node, port_index = port_index,
103 v = std::move(v)]()
mutable {
104 if(
auto n = weak_node.lock())
106 n->template control_updated_from_ui<control_value_type, NPred>(
107 std::move(v), port_index);
114template <
typename Node,
typename Field>
117 using ExecNode = safe_node<Node>;
122 const std::shared_ptr<ExecNode>& node_ptr;
125 void invoke_update(Field& param,
int k)
127 avnd::effect_container<Node>& eff = node_ptr->impl;
129 for(
auto state : eff.full_state())
131 if constexpr(avnd::dynamic_ports_port<Field>)
133 if_possible(param.ports[k].update(state.effect));
137 if_possible(param.update(state.effect));
143template <
typename Node,
typename Field, std::
size_t N, std::
size_t NField>
146template <
typename Node,
typename Field, std::
size_t N, std::
size_t NField>
149 using ExecNode = safe_node<Node>;
155 if constexpr(avnd::dynamic_ports_port<Field>)
157 using port_type = avnd::dynamic_port_type<Field>;
158 if constexpr(avnd::parameter_port<port_type>)
160 if constexpr(!
requires { param.ports[0].value.reset(); })
162 this->node_ptr->from_ossia_value(
163 param, inlet->value(), param.ports[k].value, avnd::field_index<NField>{});
169 if constexpr(!
requires { param.value.reset(); })
171 this->node_ptr->from_ossia_value(
172 param, inlet->value(), param.value, avnd::field_index<NField>{});
180 if constexpr(
requires { param.update_controller; })
182 param.update_controller
183 = [inlet = QPointer{inlet}, self = QPointer{&this->element}](
auto&& value) {
189 ossia::qt::run_async(qApp, [self, inlet, val = std::move(value)] {
195 static const Field field;
196 oscr::to_ossia_value(field, val);
197 inlet->setValue(val);
210 if constexpr(
requires { control_data.m_connectedControls; })
212 auto it = control_data.m_connectedControls.find(inlet);
213 if(it != control_data.m_connectedControls.end())
215 if constexpr(!avnd::dynamic_ports_port<Field>)
217 if(it->second.first == k)
219 QObject::disconnect(it->second.second);
220 control_data.m_connectedControls.erase(it);
225 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
226 QMetaObject::Connection connection;
227 if constexpr(avnd::dynamic_ports_port<Field>)
229 connection = QObject::connect(
230 inlet, &Process::ControlInlet::valueChanged, this->parent,
235 connection = QObject::connect(
236 inlet, &Process::ControlInlet::valueChanged, this->parent,
240 if constexpr(
requires { control_data.m_connectedControls; })
241 control_data.m_connectedControls.emplace(inlet, std::pair{k, connection});
250 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
251 if constexpr(avnd::dynamic_ports_port<Field>)
264 void connect_control_to_ui(
268 reconnect_control_to_ui(control_data, param, inlet, k);
269 this->update_controller(param, inlet);
273template <
typename Node, avnd::soundfile_port Field, std::
size_t N, std::
size_t NField>
277 using ExecNode = safe_node<Node>;
284 if(
auto hdl = loadSoundfile(inlet->value(), this->ctx.doc, this->ctx.execState))
285 this->node_ptr->soundfile_loaded(
286 hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
289 void connect_control_to_ui(
294 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
295 std::weak_ptr<ossia::execution_state> weak_st = this->ctx.execState;
297 inlet, &Process::ControlInlet::valueChanged, this->parent,
298 [&ctx = this->ctx, weak_node = std::move(weak_node),
299 weak_st = std::move(weak_st)](
const ossia::value& v) {
300 if(
auto n = weak_node.lock())
301 if(
auto st = weak_st.lock())
302 if(
auto file = loadSoundfile(v, ctx.doc, st))
304 ctx.executionQueue.enqueue([f = std::move(file), weak_node]() mutable {
305 auto n = weak_node.lock();
311 f = n->soundfile_loaded(
312 f, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
319template <
typename Node, avnd::m
idifile_port Field, std::
size_t N, std::
size_t NField>
320struct setup_control_for_exec<Node, Field, N, NField>
321 : setup_control_for_exec_base<Node, Field>
323 using ExecNode = safe_node<Node>;
324 using Model = ProcessModel<Node>;
331 if(
auto hdl = loadMidifile(inlet->value(), this->ctx.doc))
332 this->node_ptr->midifile_loaded(
333 hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
336 void connect_control_to_ui(
341 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
342 std::weak_ptr<ossia::execution_state> weak_st = this->ctx.execState;
344 inlet, &Process::ControlInlet::valueChanged, this->parent,
345 [inlet, &ctx = this->ctx,
346 weak_node = std::move(weak_node)](
const ossia::value& v) {
347 if(
auto n = weak_node.lock())
348 if(
auto file = loadMidifile(v, ctx.doc))
350 ctx.executionQueue.enqueue([f = std::move(file), weak_node]() mutable {
351 auto n = weak_node.lock();
357 f = n->midifile_loaded(
358 f, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
365template <
typename Node, avnd::raw_file_port Field, std::
size_t N, std::
size_t NField>
366struct setup_control_for_exec<
Node, Field, N, NField>
367 : setup_control_for_exec_base<Node, Field>
369 using ExecNode = safe_node<Node>;
370 using Model = ProcessModel<Node>;
372 static constexpr bool has_text =
requires {
decltype(Field::file)::text; };
373 static constexpr bool has_mmap =
requires {
decltype(Field::file)::mmap; };
380 if(
auto hdl = loadRawfile(inlet->value(), this->ctx.doc, has_text, has_mmap))
382 if constexpr(avnd::port_can_process<Field>)
386 auto func = executePortPreprocess<Field>(*hdl);
387 this->node_ptr->file_loaded(
388 hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
390 func(this->node_ptr->impl.effect);
394 this->node_ptr->file_loaded(
395 hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
400 void connect_control_to_ui(
405 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
406 std::weak_ptr<ossia::execution_state> weak_st = this->ctx.execState;
408 inlet, &Process::ControlInlet::valueChanged, this->parent,
409 [inlet, &ctx = this->ctx, weak_node = std::move(weak_node)] {
410 if(
auto n = weak_node.lock())
411 if(
auto file = loadRawfile(inlet->value(), ctx.doc, has_text, has_mmap))
413 if constexpr(avnd::port_can_process<Field>)
415 auto func = executePortPreprocess<Field>(*file);
416 ctx.executionQueue.enqueue(
417 [f = std::move(file), weak_node, ff = std::move(func)]() mutable {
418 auto n = weak_node.lock();
425 f, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
432 ctx.executionQueue.enqueue([f = std::move(file), weak_node]() mutable {
433 auto n = weak_node.lock();
440 f, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
452template <
typename Node, folder_control_port Field, std::
size_t N, std::
size_t NField>
453struct setup_control_for_exec<
Node, Field, N, NField>
454 : setup_control_for_exec_base<Node, Field>
456 using ExecNode = safe_node<Node>;
457 using Model = ProcessModel<Node>;
461 if constexpr(!
requires { param.value.reset(); })
463 this->node_ptr->from_ossia_value(
464 param, resolvePathValue(inlet->value(), this->ctx.doc), param.value,
465 avnd::field_index<NField>{});
469 void connect_control_to_ui(
473 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
475 inlet, &Process::ControlInlet::valueChanged, this->parent,
476 [&ctx = this->ctx, weak_node = std::move(weak_node),
477 field = ¶m](
const ossia::value& val) {
480 con_unvalidated<Node, Field, N, NField>{ctx, weak_node, *field}(
481 resolvePathValue(val, ctx.doc));
489template <
typename Field>
491 = !ossia_port<avnd::concrete_port_type<Field>>
492 && (!avnd::dynamic_ports_port<Field>
493 || avnd::parameter_port<avnd::concrete_port_type<Field>>);
495template <
typename Node>
498 using ExecNode = safe_node<Node>;
503 const std::shared_ptr<ExecNode>& node_ptr;
508 template <
typename Field, std::
size_t N, std::
size_t NField>
510 operator()(Field& param, avnd::predicate_index<N> np, avnd::field_index<NField> nf)
512 const auto ports = element.avnd_input_idx_to_model_ports(NField);
514 if constexpr(avnd::dynamic_ports_port<Field>)
516 param.ports.resize(ports.size());
519 if constexpr(field_has_ui_controls<Field>)
524 if(
auto inlet = qobject_cast<Process::ControlInlet*>(p))
527 element, ctx, node_ptr, parent};
529 setup.initialize_control(param, inlet, k);
531 setup.invoke_update(param, k);
533 setup.connect_control_to_ui(control_data, param, inlet, k);
543template <
typename Node>
546 using ExecNode = safe_node<Node>;
551 const std::shared_ptr<ExecNode>& node_ptr;
556 template <
typename Field, std::
size_t N, std::
size_t NField>
558 operator()(Field& param, avnd::predicate_index<N> np, avnd::field_index<NField> nf)
560 if constexpr(field_has_ui_controls<Field>)
562 const auto ports = element.avnd_input_idx_to_model_ports(NField);
566 if(
auto inlet = qobject_cast<Process::ControlInlet*>(p))
569 element, ctx, node_ptr, parent};
574 if(setup.reconnect_control_to_ui(control_data, param, inlet, k))
575 setup.push_current_value(param, inlet, k);
Definition score-plugin-avnd/Crousti/ProcessModel.hpp:88
Definition ExecutorPortSetup.hpp:36
TreeNode< DeviceExplorerNode > Node
Definition DeviceNode.hpp:74
Definition Controls.hpp:27
constexpr bool field_has_ui_controls
Definition ExecutorPortSetup.hpp:491
Definition ExecutionContext.hpp:196
Definition PortForward.hpp:23
Definition PortForward.hpp:27
Definition ExecutorPortSetup.hpp:81
Definition ExecutorPortSetup.hpp:42
Definition ExecutorPortSetup.hpp:545
Definition ExecutorPortSetup.hpp:497
Definition ExecutorPortSetup.hpp:15
Definition ExecutorPortSetup.hpp:116
Definition ExecutorPortSetup.hpp:148
bool reconnect_control_to_ui(dynamic_ports_component_data< Node > &control_data, Field ¶m, Process::ControlInlet *inlet, int k)
Definition ExecutorPortSetup.hpp:206
void push_current_value(Field ¶m, Process::ControlInlet *inlet, int k)
Definition ExecutorPortSetup.hpp:248