2#include <AvndProcesses/Utils.hpp>
3#include <Process/Process.hpp>
5#include <Crousti/File.hpp>
6#include <Crousti/ProcessModel.hpp>
8#include <ossia/detail/flat_map.hpp>
10#include <avnd/binding/ossia/node.hpp>
23template <oscr::has_dynamic_ports T>
28 ossia::flat_map<Process::Inlet*, std::pair<int, QMetaObject::Connection>>
38 ||
requires { T::placeholders(); })
40 { t.value } -> std::convertible_to<std::string_view>;
45template <
typename Field>
48 if constexpr(
requires { Field::placeholders(); })
50 if(
auto str = v.target<std::string>(); str && !str->empty())
51 return ossia::value{avnd_tools::filter_filename(*str, ctx).toStdString()};
55 return resolvePathValue(v, ctx);
58template <
typename Node,
typename Field, std::
size_t NPred, std::
size_t NField>
61 using ExecNode = safe_node<Node>;
63 std::weak_ptr<ExecNode> weak_node;
71 static constexpr std::size_t control_index
72 = avnd::control_input_introspection<Node>::field_index_to_index(
73 avnd::field_index<NField>{});
75 void operator()(
const ossia::value& val)
77 using control_value_type = std::decay_t<
decltype(Field::value)>;
79 if(
auto node = weak_node.lock())
82 node->from_ossia_value(field, val, v, avnd::field_index<NField>{});
83 ctx.executionQueue.enqueue([weak_node = weak_node, v = std::move(v)]()
mutable {
84 if(
auto n = weak_node.lock())
86 n->template control_updated_from_ui<control_value_type, control_index>(
97template <
typename Node,
typename Field, std::
size_t NPred, std::
size_t NField>
100 using ExecNode = safe_node<Node>;
102 std::weak_ptr<ExecNode> weak_node;
105 void operator()(
const ossia::value& val)
107 using control_type = avnd::dynamic_port_type<Field>;
108 using control_value_type = std::decay_t<
decltype(control_type::value)>;
110 if(
auto node = weak_node.lock())
117 control_type witness{};
118 control_value_type v;
119 node->from_ossia_value(witness, val, v, avnd::field_index<NField>{});
120 ctx.executionQueue.enqueue([weak_node = weak_node, port_index = port_index,
121 v = std::move(v)]()
mutable {
122 if(
auto n = weak_node.lock())
124 n->template control_updated_from_ui<control_value_type, NPred>(
125 std::move(v), port_index);
132template <
typename Node,
typename Field>
135 using ExecNode = safe_node<Node>;
140 const std::shared_ptr<ExecNode>& node_ptr;
143 void invoke_update(Field& param,
int k)
145 avnd::effect_container<Node>& eff = node_ptr->impl;
147 for(
auto state : eff.full_state())
149 if constexpr(avnd::dynamic_ports_port<Field>)
151 avnd::update_if_holding_value(state, param.ports[k]);
155 avnd::update_if_holding_value(state, param);
161template <
typename Node,
typename Field, std::
size_t N, std::
size_t NField>
164template <
typename Node,
typename Field, std::
size_t N, std::
size_t NField>
167 using ExecNode = safe_node<Node>;
173 if constexpr(avnd::dynamic_ports_port<Field>)
175 using port_type = avnd::dynamic_port_type<Field>;
176 if constexpr(avnd::parameter_port<port_type>)
178 if constexpr(!
requires { param.ports[0].value.reset(); })
180 this->node_ptr->from_ossia_value(
181 param, inlet->value(), param.ports[k].value, avnd::field_index<NField>{});
187 if constexpr(!
requires { param.value.reset(); })
189 this->node_ptr->from_ossia_value(
190 param, inlet->value(), param.value, avnd::field_index<NField>{});
198 if constexpr(
requires { param.update_controller; })
200 param.update_controller
201 = [inlet = QPointer{inlet}, self = QPointer{&this->element}](
auto&& value) {
207 ossia::qt::run_async(qApp, [self, inlet, val = std::move(value)] {
213 static const Field field;
214 oscr::to_ossia_value(field, val);
215 inlet->setValue(val);
228 if constexpr(
requires { control_data.m_connectedControls; })
230 auto it = control_data.m_connectedControls.find(inlet);
231 if(it != control_data.m_connectedControls.end())
233 if constexpr(!avnd::dynamic_ports_port<Field>)
235 if(it->second.first == k)
237 QObject::disconnect(it->second.second);
238 control_data.m_connectedControls.erase(it);
243 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
244 QMetaObject::Connection connection;
245 if constexpr(avnd::dynamic_ports_port<Field>)
247 connection = QObject::connect(
248 inlet, &Process::ControlInlet::valueChanged, this->parent,
253 connection = QObject::connect(
254 inlet, &Process::ControlInlet::valueChanged, this->parent,
258 if constexpr(
requires { control_data.m_connectedControls; })
259 control_data.m_connectedControls.emplace(inlet, std::pair{k, connection});
268 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
269 if constexpr(avnd::dynamic_ports_port<Field>)
282 void connect_control_to_ui(
286 reconnect_control_to_ui(control_data, param, inlet, k);
287 this->update_controller(param, inlet);
291template <
typename Node, avnd::soundfile_port Field, std::
size_t N, std::
size_t NField>
295 using ExecNode = safe_node<Node>;
302 if(
auto hdl = loadSoundfile(inlet->value(), this->ctx.doc, this->ctx.execState))
303 this->node_ptr->soundfile_loaded(
304 hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
307 void connect_control_to_ui(
312 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
313 std::weak_ptr<ossia::execution_state> weak_st = this->ctx.execState;
315 inlet, &Process::ControlInlet::valueChanged, this->parent,
316 [&ctx = this->ctx, weak_node = std::move(weak_node),
317 weak_st = std::move(weak_st)](
const ossia::value& v) {
318 if(
auto n = weak_node.lock())
319 if(
auto st = weak_st.lock())
320 if(
auto file = loadSoundfile(v, ctx.doc, st))
322 ctx.executionQueue.enqueue([f = std::move(file), weak_node]() mutable {
323 auto n = weak_node.lock();
329 f = n->soundfile_loaded(
330 f, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
337template <
typename Node, avnd::m
idifile_port Field, std::
size_t N, std::
size_t NField>
338struct setup_control_for_exec<Node, Field, N, NField>
339 : setup_control_for_exec_base<Node, Field>
341 using ExecNode = safe_node<Node>;
342 using Model = ProcessModel<Node>;
349 if(
auto hdl = loadMidifile(inlet->value(), this->ctx.doc))
350 this->node_ptr->midifile_loaded(
351 hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
354 void connect_control_to_ui(
359 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
360 std::weak_ptr<ossia::execution_state> weak_st = this->ctx.execState;
362 inlet, &Process::ControlInlet::valueChanged, this->parent,
363 [inlet, &ctx = this->ctx,
364 weak_node = std::move(weak_node)](
const ossia::value& v) {
365 if(
auto n = weak_node.lock())
366 if(
auto file = loadMidifile(v, ctx.doc))
368 ctx.executionQueue.enqueue([f = std::move(file), weak_node]() mutable {
369 auto n = weak_node.lock();
375 f = n->midifile_loaded(
376 f, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
383template <
typename Node, avnd::raw_file_port Field, std::
size_t N, std::
size_t NField>
384struct setup_control_for_exec<
Node, Field, N, NField>
385 : setup_control_for_exec_base<Node, Field>
387 using ExecNode = safe_node<Node>;
388 using Model = ProcessModel<Node>;
390 static constexpr bool has_text =
requires {
decltype(Field::file)::text; };
391 static constexpr bool has_mmap =
requires {
decltype(Field::file)::mmap; };
398 if(
auto hdl = loadRawfile(inlet->value(), this->ctx.doc, has_text, has_mmap))
400 if constexpr(avnd::port_can_process<Field>)
404 auto func = executePortPreprocess<Field>(*hdl);
405 this->node_ptr->file_loaded(
406 hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
408 func(this->node_ptr->impl.effect);
412 this->node_ptr->file_loaded(
413 hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
418 void connect_control_to_ui(
423 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
424 std::weak_ptr<ossia::execution_state> weak_st = this->ctx.execState;
426 inlet, &Process::ControlInlet::valueChanged, this->parent,
427 [inlet, &ctx = this->ctx, weak_node = std::move(weak_node)] {
428 if(
auto n = weak_node.lock())
429 if(
auto file = loadRawfile(inlet->value(), ctx.doc, has_text, has_mmap))
431 if constexpr(avnd::port_can_process<Field>)
433 auto func = executePortPreprocess<Field>(*file);
434 ctx.executionQueue.enqueue(
435 [f = std::move(file), weak_node, ff = std::move(func)]() mutable {
436 auto n = weak_node.lock();
443 f, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
450 ctx.executionQueue.enqueue([f = std::move(file), weak_node]() mutable {
451 auto n = weak_node.lock();
458 f, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
470template <
typename Node, folder_control_port Field, std::
size_t N, std::
size_t NField>
471struct setup_control_for_exec<
Node, Field, N, NField>
472 : setup_control_for_exec_base<Node, Field>
474 using ExecNode = safe_node<Node>;
475 using Model = ProcessModel<Node>;
479 if constexpr(!
requires { param.value.reset(); })
481 this->node_ptr->from_ossia_value(
482 param, resolveControlPath<Field>(inlet->value(), this->ctx.doc), param.value,
483 avnd::field_index<NField>{});
487 void connect_control_to_ui(
491 std::weak_ptr<ExecNode> weak_node = this->node_ptr;
493 inlet, &Process::ControlInlet::valueChanged, this->parent,
494 [&ctx = this->ctx, weak_node = std::move(weak_node),
495 field = ¶m](
const ossia::value& val) {
498 con_unvalidated<Node, Field, N, NField>{ctx, weak_node, *field}(
499 resolveControlPath<Field>(val, ctx.doc));
507template <
typename Field>
509 = !ossia_port<avnd::concrete_port_type<Field>>
510 && (!avnd::dynamic_ports_port<Field>
511 || avnd::parameter_port<avnd::concrete_port_type<Field>>);
513template <
typename Node>
516 using ExecNode = safe_node<Node>;
521 const std::shared_ptr<ExecNode>& node_ptr;
526 template <
typename Field, std::
size_t N, std::
size_t NField>
528 operator()(Field& param, avnd::predicate_index<N> np, avnd::field_index<NField> nf)
530 const auto ports = element.avnd_input_idx_to_model_ports(NField);
532 if constexpr(avnd::dynamic_ports_port<Field>)
534 param.ports.resize(ports.size());
537 if constexpr(field_has_ui_controls<Field>)
542 if(
auto inlet = qobject_cast<Process::ControlInlet*>(p))
545 element, ctx, node_ptr, parent};
547 setup.initialize_control(param, inlet, k);
549 setup.invoke_update(param, k);
551 setup.connect_control_to_ui(control_data, param, inlet, k);
561template <
typename Node>
564 using ExecNode = safe_node<Node>;
569 const std::shared_ptr<ExecNode>& node_ptr;
574 template <
typename Field, std::
size_t N, std::
size_t NField>
576 operator()(Field& param, avnd::predicate_index<N> np, avnd::field_index<NField> nf)
578 if constexpr(field_has_ui_controls<Field>)
580 const auto ports = element.avnd_input_idx_to_model_ports(NField);
584 if(
auto inlet = qobject_cast<Process::ControlInlet*>(p))
587 element, ctx, node_ptr, parent};
592 if(setup.reconnect_control_to_ui(control_data, param, inlet, k))
593 setup.push_current_value(param, inlet, k);
Definition score-plugin-avnd/Crousti/ProcessModel.hpp:88
Definition ExecutorPortSetup.hpp:37
TreeNode< DeviceExplorerNode > Node
Definition DeviceNode.hpp:74
Definition Controls.hpp:27
ossia::value resolveControlPath(const ossia::value &v, const score::DocumentContext &ctx)
Definition ExecutorPortSetup.hpp:46
constexpr bool field_has_ui_controls
Definition ExecutorPortSetup.hpp:509
Definition ExecutionContext.hpp:201
Definition PortForward.hpp:23
Definition PortForward.hpp:27
Definition ExecutorPortSetup.hpp:99
Definition ExecutorPortSetup.hpp:60
Definition ExecutorPortSetup.hpp:563
Definition ExecutorPortSetup.hpp:515
Definition ExecutorPortSetup.hpp:16
Definition ExecutorPortSetup.hpp:134
Definition ExecutorPortSetup.hpp:166
bool reconnect_control_to_ui(dynamic_ports_component_data< Node > &control_data, Field ¶m, Process::ControlInlet *inlet, int k)
Definition ExecutorPortSetup.hpp:224
void push_current_value(Field ¶m, Process::ControlInlet *inlet, int k)
Definition ExecutorPortSetup.hpp:266
Definition DocumentContext.hpp:18