From e4dd667269fd58e27a2916f0940678ec26ff8d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Sun, 28 Jul 2024 18:35:24 -0400 Subject: [PATCH] [dynamic ports] Improve api --- examples/Raw/DynamicPort.hpp | 166 ++++++++++++++++++ .../binding/ossia/port_run_postprocess.hpp | 10 +- .../binding/ossia/port_run_preprocess.hpp | 12 +- include/avnd/binding/ossia/port_setup.hpp | 19 +- include/avnd/concepts/all.hpp | 1 + 5 files changed, 194 insertions(+), 14 deletions(-) create mode 100644 examples/Raw/DynamicPort.hpp diff --git a/examples/Raw/DynamicPort.hpp b/examples/Raw/DynamicPort.hpp new file mode 100644 index 00000000..43bc3a44 --- /dev/null +++ b/examples/Raw/DynamicPort.hpp @@ -0,0 +1,166 @@ +#pragma once +#include + +#include +#include + +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +namespace examples +{ +struct SumPorts +{ + static constexpr auto name() { return "Sum"; } + static constexpr auto c_name() { return "avnd_sumports"; } + static constexpr auto author() { return "Jean-Michaƫl Celerier"; } + static constexpr auto category() { return "Debug"; } + static constexpr auto description() + { + return "Example of an object with dynamic number of inputs"; + } + static constexpr auto uuid() { return "48b57b3e-227a-4a55-adce-86c011dcf491"; } + + struct inputs + { + struct + { + static constexpr auto name() { return "Control"; } + enum widget + { + spinbox + }; + struct range + { + int min = 0, max = 10, init = 0; + }; + int value = 0; + + static std::function on_controller_setup() + { + return [](SumPorts& object, int value) { + object.inputs.in_i.request_port_resize(value); + object.outputs.out_i.request_port_resize(value); + }; + } + static std::function on_controller_interaction() + { + return [](SumPorts& object, int value) { + object.inputs.in_i.request_port_resize(value); + object.outputs.out_i.request_port_resize(value); + }; + } + } controller; + + struct + { + struct port + { + static constexpr auto name() { return "Input {}"; } + struct range + { + double min = 0, max = 1, init = 0; + }; + enum widget + { + knob + }; + double value; + }; + std::vector ports{}; + std::function request_port_resize; + } in_i; + } inputs; + + struct + { + struct + { + static constexpr auto name() { return "Output"; } + double value{}; + } out; + struct + { + static constexpr auto name() { return "C"; } + double value{}; + } c; + + struct + { + struct port + { + static constexpr auto name() { return "Output {}"; } + double value; + }; + std::vector ports{}; + std::function request_port_resize; + } out_i; + } outputs; + + double filtered{}; + void operator()() + { + outputs.out.value = 0; + int k = 0; + const int N = inputs.in_i.ports.size(); + + outputs.c.value = N; + + for(auto val : inputs.in_i.ports) + outputs.out.value += std::pow(10, k++) * std::floor(10 * val.value); + for(int i = 0; i < N; i++) + outputs.out_i.ports[i].value = inputs.in_i.ports[i].value; + } + + struct ui + { + static constexpr auto name() { return "Main"; } + static constexpr auto layout() + { + enum + { + hbox + }; + return hbox; + } + struct + { + static constexpr auto layout() + { + enum + { + control + }; + return control; + } + decltype(&inputs::controller) model = &inputs::controller; + } float_widget; + + struct + { + static constexpr auto layout() + { + enum + { + control + }; + return control; + } + decltype(&inputs::in_i) model = &inputs::in_i; + } multi_widget; + }; +}; +} + +// Adding a new concept. +// Process. +// 1. Specifying the concept: +// avnd/concepts/dynamic_port.hpp + +// 2. Specify the introspection struct +// avnd/introspection/port.hpp + +// 3. Specify the input or output (or both) introspection struct +// avnd/introspection/input.hpp + +// 4. Create a filter +// avnd/binding/ossia/dynamic_ports.hpp diff --git a/include/avnd/binding/ossia/port_run_postprocess.hpp b/include/avnd/binding/ossia/port_run_postprocess.hpp index 96d7c80b..df428f50 100644 --- a/include/avnd/binding/ossia/port_run_postprocess.hpp +++ b/include/avnd/binding/ossia/port_run_postprocess.hpp @@ -101,14 +101,18 @@ struct process_after_run write_value(ctrl, port, ctrl.value, 0, avnd::field_index{}); } - template + template void operator()( Field& ctrl, std::vector& port, avnd::field_index) const noexcept { int N = port.size(); - - write_value(ctrl, port, ctrl.value, 0, avnd::field_index{}); + assert(N == ctrl.ports.size()); + for(int i = 0; i < N; i++) + { + write_value( + ctrl.ports[i], *port[i], ctrl.ports[i].value, 0, avnd::field_index{}); + } } template diff --git a/include/avnd/binding/ossia/port_run_preprocess.hpp b/include/avnd/binding/ossia/port_run_preprocess.hpp index 25b8fb1a..75c783a4 100644 --- a/include/avnd/binding/ossia/port_run_preprocess.hpp +++ b/include/avnd/binding/ossia/port_run_preprocess.hpp @@ -61,7 +61,7 @@ struct process_before_run } } - template + template void init_value( Field& ctrl, std::vector& ports, avnd::field_index idx) const noexcept @@ -77,8 +77,7 @@ struct process_before_run auto& last = port.data.get_data().back().value; // FIXME check optional ports case - written |= self.from_ossia_value(ctrl, last, ctrl.ports[p], idx); - qDebug() << ossia::value_to_pretty_string(last) << p << ctrl.ports[p]; + written |= self.from_ossia_value(ctrl.ports[p], last, ctrl.ports[p].value, idx); // FIXME // if constexpr(avnd::control) @@ -108,7 +107,8 @@ struct process_before_run { init_value(ctrl, port, avnd::field_index{}); } - template + + template void operator()( Field& ctrl, std::vector& port, avnd::field_index idx) const noexcept @@ -406,7 +406,7 @@ struct process_before_run } } - template + template void operator()( Field& ctrl, std::vector& ports, avnd::field_index) const noexcept @@ -414,7 +414,7 @@ struct process_before_run ctrl.ports.resize(ports.size()); for(auto& port_value : ctrl.ports) { - port_value = {}; + port_value.value = {}; } } diff --git a/include/avnd/binding/ossia/port_setup.hpp b/include/avnd/binding/ossia/port_setup.hpp index 63eff3bb..56e37c6f 100644 --- a/include/avnd/binding/ossia/port_setup.hpp +++ b/include/avnd/binding/ossia/port_setup.hpp @@ -25,8 +25,13 @@ struct get_ossia_inlet_type template struct get_ossia_inlet_type { - using type = std::conditional_t< - avnd::dynamic_ports_port, std::vector, ossia::value_inlet>; + using type = ossia::value_inlet; +}; +template +struct get_ossia_inlet_type +{ + using base_type = typename decltype(T{}.ports)::value_type; + using type = std::vector::type*>; }; template struct get_ossia_inlet_type @@ -79,9 +84,13 @@ struct get_ossia_outlet_type template struct get_ossia_outlet_type { - using type = std::conditional_t< - avnd::dynamic_ports_port, std::vector, - ossia::value_outlet>; + using type = ossia::value_outlet; +}; +template +struct get_ossia_outlet_type +{ + using base_type = typename decltype(T{}.ports)::value_type; + using type = std::vector::type*>; }; template struct get_ossia_outlet_type diff --git a/include/avnd/concepts/all.hpp b/include/avnd/concepts/all.hpp index 6c5b52d2..1949ca1a 100644 --- a/include/avnd/concepts/all.hpp +++ b/include/avnd/concepts/all.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include