From 06207029e4eb06e6f7040e99ba0d1f078dd8ecb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Sun, 19 Nov 2023 15:44:29 +0100 Subject: [PATCH] [wip] Work on exposing vst3 plug-ins to OSCQuery --- cmake/avendish.cmake | 2 +- cmake/avendish.sources.cmake | 4 +- cmake/avendish.standalone.cmake | 1 - cmake/avendish.vst3.cmake | 44 ++++- examples/Helpers/Controls.hpp | 2 +- examples/Raw/Interpolator.hpp | 55 ++++++ include/avnd/binding/max/attributes_setup.hpp | 5 +- include/avnd/binding/ossia/from_value.hpp | 82 ++++++++- include/avnd/binding/ossia/ossia_to_curve.hpp | 4 + .../binding/ossia/port_run_preprocess.hpp | 10 +- include/avnd/binding/ossia/qt.hpp | 41 +++++ .../binding/standalone/oscquery_mapper.hpp | 164 +++++------------- .../standalone/oscquery_minimal_mapper.hpp | 117 +++++++++++++ .../avnd/binding/standalone/prototype.cpp.in | 18 +- .../avnd/binding/standalone/standalone.hpp | 6 +- include/avnd/binding/ui/qml/enum_control.hpp | 36 +++- include/avnd/binding/ui/qml/enum_ui.hpp | 3 +- include/avnd/binding/ui/qml/float_control.hpp | 11 +- include/avnd/binding/ui/qml/float_knob.hpp | 1 - include/avnd/binding/ui/qml/float_slider.hpp | 1 - include/avnd/binding/ui/qml/int_control.hpp | 11 +- include/avnd/binding/ui/qml/int_knob.hpp | 1 - include/avnd/binding/ui/qml/int_slider.hpp | 1 - .../avnd/binding/ui/qml/toggle_control.hpp | 17 +- include/avnd/binding/ui/qml/toggle_ui.hpp | 16 +- include/avnd/binding/ui/qml_layout_ui.hpp | 32 +++- include/avnd/binding/ui/qml_ui.hpp | 35 +++- include/avnd/binding/vst3/controller.hpp | 16 +- include/avnd/binding/vst3/helpers.hpp | 5 +- include/avnd/binding/vst3/prototype.cpp.in | 110 ++++++------ include/avnd/introspection/widgets.hpp | 86 ++++++--- include/avnd/wrappers/metadatas.hpp | 7 + 32 files changed, 676 insertions(+), 268 deletions(-) create mode 100644 examples/Raw/Interpolator.hpp create mode 100644 include/avnd/binding/ossia/qt.hpp create mode 100644 include/avnd/binding/standalone/oscquery_minimal_mapper.hpp diff --git a/cmake/avendish.cmake b/cmake/avendish.cmake index 3d4266f4..c02c7847 100644 --- a/cmake/avendish.cmake +++ b/cmake/avendish.cmake @@ -9,7 +9,7 @@ set(AVND_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "") find_package(Boost QUIET REQUIRED) find_package(Threads QUIET) find_package(fmt QUIET) - +find_package(ossia QUIET) set(AVENDISH_SOURCES "${AVND_SOURCE_DIR}/include/avnd/concepts/all.hpp" diff --git a/cmake/avendish.sources.cmake b/cmake/avendish.sources.cmake index 889987dc..5b3126bd 100644 --- a/cmake/avendish.sources.cmake +++ b/cmake/avendish.sources.cmake @@ -72,7 +72,7 @@ function(avnd_target_setup AVND_FX_TARGET) target_compile_options( ${AVND_FX_TARGET} PUBLIC - -stdlib=libc++ + # -stdlib=libc++ # -flto -fno-stack-protector -fno-ident @@ -133,7 +133,7 @@ function(avnd_target_setup AVND_FX_TARGET) ) elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") target_link_libraries(${AVND_FX_TARGET} PRIVATE - -lc++ + # -lc++ -Bsymbolic # -flto ) diff --git a/cmake/avendish.standalone.cmake b/cmake/avendish.standalone.cmake index dcaf1bb3..b15f5242 100644 --- a/cmake/avendish.standalone.cmake +++ b/cmake/avendish.standalone.cmake @@ -3,7 +3,6 @@ if(CMAKE_SYSTEM_NAME MATCHES "WAS.*") endfunction() return() endif() -find_package(ossia) find_package(GLEW QUIET) find_package(glfw3 QUIET) find_package(OpenGL QUIET) diff --git a/cmake/avendish.vst3.cmake b/cmake/avendish.vst3.cmake index 673620d7..a78680b6 100644 --- a/cmake/avendish.vst3.cmake +++ b/cmake/avendish.vst3.cmake @@ -29,6 +29,15 @@ if(NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-non-virtual-dtor") endif() +if(APPLE) + set(VST3_DYNAMIC_LIST "_BundleEntry\n_BundleExit\n_bundleEntry\n_bundleExit\n_GetPluginFactory") +elseif(WIN32) + set(VST3_DYNAMIC_LIST "AVND {\nlocal:*;\nglobal:InitDll;\nExitDll;\nGetPluginFactory;\n};\n") +else() + set(VST3_DYNAMIC_LIST "AVND {\n global:\n ModuleEntry;\n ModuleExit;\n GetPluginFactory;\n local:\n *;\n};\n") +endif() + +file(WRITE "${CMAKE_BINARY_DIR}/vst3_symbols" "${VST3_DYNAMIC_LIST}") add_subdirectory("${VST3_SDK_ROOT}" "${CMAKE_BINARY_DIR}/vst3_sdk") function(avnd_make_vst3) @@ -62,9 +71,42 @@ function(avnd_make_vst3) ${AVND_FX_TARGET} PUBLIC Avendish::Avendish_vst3 - sdk_common pluginterfaces + $ DisableExceptions ) + + if(UNIX AND NOT APPLE) + target_link_libraries( + ${AVND_FX_TARGET} + PUBLIC + -Wl,-z,defs + ) + endif() + + if(APPLE) + target_link_libraries(${AVND_FX_TARGET} PRIVATE "-Wl, -exported_symbols_list ,${CMAKE_BINARY_DIR}/vst3_symbols") + elseif(WIN32) + if(NOT MSVC) + target_link_libraries(${AVND_FX_TARGET} PRIVATE "-Wl,--version-script=${CMAKE_BINARY_DIR}/vst3_symbols") + endif() + else() + target_link_libraries(${AVND_FX_TARGET} PRIVATE "-Wl,--version-script=${CMAKE_BINARY_DIR}/vst3_symbols") + endif() + + + if(TARGET ossia::ossia) + target_compile_definitions( + ${AVND_FX_TARGET} + PUBLIC + AVND_ADD_OSCQUERY_BINDINGS=1 + ) + target_link_libraries( + ${AVND_FX_TARGET} + PUBLIC + ossia::ossia + ) + endif() + if(APPLE) find_library(COREFOUNDATION_FK CoreFoundation) target_link_libraries( diff --git a/examples/Helpers/Controls.hpp b/examples/Helpers/Controls.hpp index 71ba432b..4ddfa921 100644 --- a/examples/Helpers/Controls.hpp +++ b/examples/Helpers/Controls.hpp @@ -58,7 +58,7 @@ struct Controls struct range { - halp::combo_pair values[3]{{"Foo", 0.1f}, {"Bar", 0.5f}, {"Baz", 0.8f}}; + halp::combo_pair values[3]{{"A", 0.1f}, {"B", 0.5f}, {"C", 0.8f}}; int init{1}; // Bar }; diff --git a/examples/Raw/Interpolator.hpp b/examples/Raw/Interpolator.hpp new file mode 100644 index 00000000..17467926 --- /dev/null +++ b/examples/Raw/Interpolator.hpp @@ -0,0 +1,55 @@ +#pragma once + +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include +#include + +namespace examples +{ +struct ExponentialSmoothing +{ + static constexpr auto name() { return "Exponential Smoothing"; } + static constexpr auto c_name() { return "avnd_expsmooth"; } + static constexpr auto uuid() { return "971739ae-14a3-4283-b0a0-96dbd367ce66"; } + + struct + { + struct + { + static constexpr auto name() { return "Input"; } + double value{}; + } in; + + struct + { + static constexpr auto name() { return "Alpha"; } + struct range + { + double min{0.01}, max{1.}, init{0.5}; + }; + double value{range{}.init}; + } alpha; + } inputs; + + struct + { + struct + { + static constexpr auto name() { return "Output"; } + double value{}; + } out; + } outputs; + + double filtered{}; + void operator()() + { + const double in = this->inputs.in.value; + const double a = this->inputs.alpha.value; + + filtered = in * a + filtered * (1.0f - a); + outputs.out.value = filtered; + } +}; +} diff --git a/include/avnd/binding/max/attributes_setup.hpp b/include/avnd/binding/max/attributes_setup.hpp index 04c9e3e4..d887997a 100644 --- a/include/avnd/binding/max/attributes_setup.hpp +++ b/include/avnd/binding/max/attributes_setup.hpp @@ -61,10 +61,7 @@ struct attribute_register if(from_atoms{ac, av}(field.value)) { - if constexpr(requires { field.update(obj); }) - { - field.update(obj); - } + if_possible(field.update(obj)); } } return MAX_ERR_NONE; diff --git a/include/avnd/binding/ossia/from_value.hpp b/include/avnd/binding/ossia/from_value.hpp index 3f32aa54..dbcee1dd 100644 --- a/include/avnd/binding/ossia/from_value.hpp +++ b/include/avnd/binding/ossia/from_value.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -1300,9 +1301,14 @@ inline void from_ossia_value(auto& field, const ossia::value& src, auto& dst) template struct enum_from_ossia_visitor { + Val operator()(const float& v) const noexcept + { + return (*this)(int(v)); + } + Val operator()(const int& v) const noexcept { - constexpr auto range = avnd::get_range(); + static constexpr auto range = avnd::get_range(); static_assert(std::size(range.values) > 0); if constexpr(requires(Val v) { v = range.values[0].second; }) { @@ -1323,9 +1329,10 @@ struct enum_from_ossia_visitor return static_cast(v); } } + Val operator()(const std::string& v) const noexcept { - constexpr auto range = avnd::get_range(); + static constexpr auto range = avnd::get_range(); for(int i = 0; i < std::size(range.values); i++) { if constexpr(requires { v == range.values[i].first; }) @@ -1363,11 +1370,80 @@ inline void from_ossia_value(Field& field, const ossia::value& src, Val& dst) template inline void from_ossia_value(Field& field, const ossia::value& src, Val& dst) { +#if AVND_OSSIA_HAS_CURVE auto segments = src.template target>(); if(!segments) return; - convert_to_curve{}(dst, *segments); +#endif } + + + + +template +static constexpr ossia::val_type type_for_arg() +{ + if constexpr(std::floating_point) + { + return ossia::val_type::FLOAT; + } + else if constexpr(std::integral) + { + return ossia::val_type::INT; + } + else if constexpr(std::is_same_v) + { + return ossia::val_type::BOOL; + } + else if constexpr(std::is_same_v) + { + return ossia::val_type::STRING; + } + else if constexpr(std::is_same_v) + { + return ossia::val_type::STRING; + } + else if constexpr(std::is_same_v) + { + return ossia::val_type::STRING; + } + else if constexpr(std::is_same_v>) + { + return ossia::val_type::VEC2F; + } + else if constexpr(std::is_same_v>) + { + return ossia::val_type::VEC3F; + } + else if constexpr(std::is_same_v>) + { + return ossia::val_type::VEC4F; + } + else if constexpr(avnd::vector_ish || avnd::set_ish) + { + return ossia::val_type::LIST; + } + else if constexpr(avnd::map_ish) + { + return ossia::val_type::LIST; + } + else if constexpr(avnd::variant_ish) + { + return ossia::val_type::LIST; + } + else if constexpr(avnd::optional_ish) + { + return ossia::val_type::LIST; + } + else if constexpr(std::is_aggregate_v) + { + if constexpr(avnd::has_field_names) + return ossia::val_type::MAP; + else + return ossia::val_type::LIST; + } + return ossia::val_type::IMPULSE; +} } diff --git a/include/avnd/binding/ossia/ossia_to_curve.hpp b/include/avnd/binding/ossia/ossia_to_curve.hpp index 49d3401c..163aaee7 100644 --- a/include/avnd/binding/ossia/ossia_to_curve.hpp +++ b/include/avnd/binding/ossia/ossia_to_curve.hpp @@ -1,5 +1,7 @@ #pragma once #include +#if __has_include() +#define AVND_OSSIA_HAS_CURVE 1 #include #include #include @@ -259,3 +261,5 @@ struct convert_to_curve }; } + +#endif diff --git a/include/avnd/binding/ossia/port_run_preprocess.hpp b/include/avnd/binding/ossia/port_run_preprocess.hpp index 936c4819..2cf469e6 100644 --- a/include/avnd/binding/ossia/port_run_preprocess.hpp +++ b/include/avnd/binding/ossia/port_run_preprocess.hpp @@ -27,10 +27,7 @@ inline void update_value( { if(node.from_ossia_value(field, src, dst, idx)) { - if constexpr(requires { field.update(obj); }) - { - field.update(obj); - } + if_possible(field.update(obj)); } } @@ -276,10 +273,7 @@ struct process_before_run ctrl.value = dest_vec; - if constexpr(requires { ctrl.update(impl); }) - { - ctrl.update(impl); - } + if_possible(ctrl.update(impl)); } template diff --git a/include/avnd/binding/ossia/qt.hpp b/include/avnd/binding/ossia/qt.hpp new file mode 100644 index 00000000..34ffe6e4 --- /dev/null +++ b/include/avnd/binding/ossia/qt.hpp @@ -0,0 +1,41 @@ +#pragma once +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace oscr +{ +template +auto to_combobox_range(const std::string_view (&val)[N]) +{ + std::vector> vec; + for(int i = 0; i < N; i++) + vec.emplace_back(val[i].data(), i); + return vec; +} + +template +auto to_combobox_range(const std::array& val) +{ + std::vector> vec; + for(int i = 0; i < N; i++) + vec.emplace_back(val[i].data(), i); + return vec; +} + +std::vector> to_combobox_range(const auto& in) +{ + std::vector> vec; + for(auto& v : avnd::to_const_char_array(in)) + vec.emplace_back(v.first, v.second); + return vec; +} +} diff --git a/include/avnd/binding/standalone/oscquery_mapper.hpp b/include/avnd/binding/standalone/oscquery_mapper.hpp index 1acae3bc..0e98743b 100644 --- a/include/avnd/binding/standalone/oscquery_mapper.hpp +++ b/include/avnd/binding/standalone/oscquery_mapper.hpp @@ -2,6 +2,8 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ +#include +#include #include #include #include @@ -16,9 +18,7 @@ #include #include #include -#include #include - namespace standalone { template @@ -35,13 +35,14 @@ struct oscquery_mapper std::shared_ptr m_context; ossia::net::generic_device m_dev; - explicit oscquery_mapper(avnd::effect_container& object, int osc_port, int ws_port) + explicit oscquery_mapper( + avnd::effect_container& object, std::string name, int osc_port, int ws_port) : object{object} , m_context{std::make_shared()} , m_dev{ std::make_unique( m_context, osc_port, ws_port), - "my_device"} + name} { create_ports(); } @@ -50,7 +51,7 @@ struct oscquery_mapper requires(!avnd::enum_parameter) void setup_control(Field& field, ossia::net::parameter_base& param) { - param.set_value_type(type_for_arg()); + param.set_value_type(oscr::type_for_arg()); // Set-up the metadata if constexpr(avnd::parameter_with_minmax_range) @@ -63,8 +64,10 @@ struct oscquery_mapper param.set_access(ossia::access_mode::BI); // Set-up the external callback - param.add_callback([&field](const ossia::value& val) { - field.value = convert(val, tag{}); + param.add_callback([object = &object, &field](const ossia::value& val) { + oscr::from_ossia_value(field, val, field.value); + + if_possible(field.update(object.effect)); }); } @@ -82,32 +85,9 @@ struct oscquery_mapper param.set_access(ossia::access_mode::BI); // Set-up the external callback - - param.add_callback([&field](const ossia::value& val) { - if(const int* iindex = val.target()) - { - if(*iindex >= 0 && *iindex < choices_count) - { - field.value = static_cast(*iindex); - } - } - else if(const float* findex = val.target()) - { - int index = *findex; - if(index >= 0 && index < choices_count) - { - field.value = static_cast(index); - } - } - else if(const std::string* txt = val.target()) - { - auto it = std::find(choices.begin(), choices.end(), *txt); - if(it != choices.end()) - { - int index = std::distance(choices.begin(), it); - field.value = static_cast(index); - } - } + param.add_callback([object = &object, &field](const ossia::value& val) { + oscr::from_ossia_value(field, val, field.value); + if_possible(field.update(object.effect)); }); } @@ -115,9 +95,7 @@ struct oscquery_mapper void create_control(Field& field) { ossia::net::node_base& node = m_dev.get_root_node(); - std::string name = "input"; - if constexpr(requires { Field::name(); }) - name = Field::name(); + std::string name{avnd::get_path(field)}; if(auto param = ossia::net::create_parameter(node, name)) @@ -158,7 +136,9 @@ struct oscquery_mapper template static Arg convert(const ossia::value& atom, tag) { - return ossia::convert(atom); + Arg a; + oscr::from_ossia_value(atom, a); + return a; } static std::string convert(const ossia::value& atom, tag) @@ -253,6 +233,10 @@ struct oscquery_mapper { f(object.effect, ossia::convert(in)); } + else if constexpr(std::is_same_v) + { + f(object.effect, ossia::convert(in)); + } else if constexpr(std::is_same_v>) { f(object.effect, ossia::convert>(in)); @@ -350,44 +334,6 @@ struct oscquery_mapper } } - template - static constexpr ossia::val_type type_for_arg() - { - if constexpr(std::floating_point) - { - return ossia::val_type::FLOAT; - } - else if constexpr(std::integral) - { - return ossia::val_type::INT; - } - else if constexpr(std::is_same_v) - { - return ossia::val_type::BOOL; - } - else if constexpr(std::is_same_v) - { - return ossia::val_type::STRING; - } - else if constexpr(std::is_same_v) - { - return ossia::val_type::STRING; - } - else if constexpr(std::is_same_v>) - { - return ossia::val_type::VEC2F; - } - else if constexpr(std::is_same_v>) - { - return ossia::val_type::VEC3F; - } - else if constexpr(std::is_same_v>) - { - return ossia::val_type::VEC4F; - } - return ossia::val_type::IMPULSE; - } - template void init_message_arguments( ossia::net::parameter_base& param, boost::mp11::mp_list) @@ -398,7 +344,7 @@ struct oscquery_mapper } else if constexpr(sizeof...(Args) == 1) { - param.set_value_type(type_for_arg()); + param.set_value_type(oscr::type_for_arg()); } else { @@ -406,10 +352,11 @@ struct oscquery_mapper init.reserve(sizeof...(Args)); param.set_value_type(ossia::val_type::LIST); - (init.push_back(ossia::init_value(type_for_arg())), ...); + (init.push_back(ossia::init_value(oscr::type_for_arg())), ...); param.set_value(std::move(init)); } } + template void init_message_arguments( ossia::net::parameter_base& param, boost::mp11::mp_list) @@ -439,7 +386,7 @@ struct oscquery_mapper if constexpr(requires { avnd::function_reflection::count; }) { ossia::net::node_base& node = m_dev.get_root_node(); - std::string name{Field::name()}; + std::string name{avnd::get_path(field)}; if(auto param = ossia::net::create_parameter( node, name)) // TODO { @@ -467,14 +414,12 @@ struct oscquery_mapper void create_output(Field& field) { ossia::net::node_base& node = m_dev.get_root_node(); - std::string name = "output"; - if constexpr(requires { Field::name(); }) - name = Field::name(); + std::string name{avnd::get_path(field)}; if(auto param = ossia::net::create_parameter(node, name)) { - param->set_value_type(type_for_arg()); + param->set_value_type(oscr::type_for_arg()); if constexpr(avnd::has_range) { constexpr auto ctl = avnd::get_range(); @@ -485,51 +430,32 @@ struct oscquery_mapper } } - template - void create_control(Field& field) - { - } - - template - void create_output(Field& field) - { - } - void create_ports() { - /* - if constexpr (avnd::float_parameter_input_introspection::size > 0) - { - avnd::for_each_field_ref( - object.inputs(), + if constexpr(avnd::has_inputs) + avnd::parameter_input_introspection::for_all( + avnd::get_inputs(object), [this](Field& f) { create_control(f); }); - } - if constexpr (avnd::float_parameter_output_introspection::size > 0) - { - avnd::for_each_field_ref( - object.outputs(), + if constexpr(avnd::has_outputs) + avnd::parameter_output_introspection::for_all( + avnd::get_outputs(object), [this](Field& f) { create_output(f); }); - } -*/ + if constexpr(avnd::has_messages) - { - avnd::for_each_field_ref( - avnd::get_messages(object), + avnd::messages_introspection::for_all( + avnd::get_messages(object), [&](Field& f) { create_message(f); }); - } - - /* - std::vector my_params; - for(int i = 0; i < 10; i++) - { - auto& node = find_or_create_node(m_dev, "/tes t/ fo o." + std::to_string(i)); - auto param = node.create_parameter(ossia::val_type::FLOAT); - param->push_value(0.1 + 0.01 * i); - my_params.push_back(param); - } - */ + // FIXME: for callbacks we must not overwrite the callback already set + // by the binding. + // Same thing for the UI. + // -> in the end, we need to have some multiplexing layer for when we have more than 1 binding + // + // if constexpr(avnd::has_outputs) + // avnd::callback_output_introspection::for_all( + // avnd::get_outputs(object), + // [&](Field& f) { create_callback(f); }); } void run() { m_context->run(); } diff --git a/include/avnd/binding/standalone/oscquery_minimal_mapper.hpp b/include/avnd/binding/standalone/oscquery_minimal_mapper.hpp new file mode 100644 index 00000000..67a59298 --- /dev/null +++ b/include/avnd/binding/standalone/oscquery_minimal_mapper.hpp @@ -0,0 +1,117 @@ +#pragma once + +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +namespace standalone +{ +template +struct oscquery_minimal_mapper +{ + using inputs_type = typename avnd::inputs_type::type; + std::shared_ptr m_context; + ossia::net::generic_device m_dev; + std::jthread m_thread; + + explicit oscquery_minimal_mapper(std::string name, int osc_port, int ws_port) + : m_context{std::make_shared()} + , m_dev{ + std::make_unique( + m_context), + name} + { + m_thread = std::jthread([this] (std::stop_token tk){ + std::this_thread::sleep_for(std::chrono::seconds(1)); + while(!tk.stop_requested()) + { + std::cerr << ("Starting...") << std::endl; + m_context->run(); + } + std::cerr << ("Exited") << std::endl; + }); + } + + ~oscquery_minimal_mapper() + { + std::cerr <<("oh shit"); + } + + template + requires(!avnd::enum_parameter) + void setup_control(Field& field, ossia::net::parameter_base& param) + { + std::cerr << ("Adding a control") << avnd::get_name() << std::endl; + param.set_value_type(oscr::type_for_arg()); + + // Set-up the metadata + if constexpr(avnd::parameter_with_minmax_range) + { + constexpr auto ctl = avnd::get_range(); + param.set_domain(ossia::make_domain(ctl.min, ctl.max)); + param.set_value(ctl.init); + } + + param.set_access(ossia::access_mode::BI); + + // Set-up the external callback + param.add_callback([&field](const ossia::value& val) { + oscr::from_ossia_value(field, val, field.value); + // FIXME callback into the origin + }); + } + + template + void setup_control(Field& field, ossia::net::parameter_base& param) + { + param.set_value_type(ossia::val_type::STRING); + + static constexpr const auto choices = avnd::get_enum_choices(); + static constexpr const auto choices_count = choices.size(); + ossia::domain_base dom{{choices.begin(), choices.end()}}; + // Set-up the metadata + param.set_value(dom.values[(int)avnd::get_range().init]); + param.set_domain(std::move(dom)); + param.set_access(ossia::access_mode::BI); + + // Set-up the external callback + param.add_callback([&field](const ossia::value& val) { + oscr::from_ossia_value(field, val, field.value); + }); + } + + template + void create_control(Field& field) + { + ossia::net::node_base& node = m_dev.get_root_node(); + std::string name{avnd::get_path(field)}; + + if(auto param + = ossia::net::create_parameter(node, name)) + { + setup_control(field, *param); + } + } + + void create_ports(typename avnd::inputs_type::type& inputs) + { + avnd::parameter_input_introspection::for_all(inputs, + [this](Field& f) { create_control(f); }); + } +}; +} diff --git a/include/avnd/binding/standalone/prototype.cpp.in b/include/avnd/binding/standalone/prototype.cpp.in index c21a5fa5..ff18d55f 100644 --- a/include/avnd/binding/standalone/prototype.cpp.in +++ b/include/avnd/binding/standalone/prototype.cpp.in @@ -22,18 +22,18 @@ void run_ui(auto& object) #if AVND_STANDALONE_NKL if constexpr(avnd::has_ui) { - nkl::layout_ui< type > ui{object}; + nkl::layout_ui ui{object}; ui.render(); } #elif AVND_STANDALONE_QML if constexpr(avnd::has_ui) { - qml::qml_layout_ui< type > ui{object}; + qml::qml_layout_ui ui{object}; qApp->exec(); } else { - qml::qml_ui< type > ui{object}; + qml::qml_ui ui{object}; qApp->exec(); } #endif @@ -48,6 +48,7 @@ int main(int argc, char** argv) int osc_port = 1234; int ws_port = 5678; + const auto app_name = std::string(avnd::get_name()); #if AVND_STANDALONE_QML qputenv("QML_DISABLE_DISTANCEFIELD", "1"); qputenv("QT_SCALE_FACTOR", "1"); @@ -55,8 +56,7 @@ int main(int argc, char** argv) qputenv("QT_QUICK_CONTROLS_STYLE", "Material"); qputenv("QT_QUICK_CONTROLS_MATERIAL_THEME", "Dark"); - QCoreApplication::setApplicationName( - QString::fromStdString(std::string(avnd::get_name()))); + QCoreApplication::setApplicationName(QString::fromStdString(app_name)); QCoreApplication::setApplicationVersion( QString::fromStdString(std::string(avnd::get_version()))); QCoreApplication::setOrganizationName( @@ -119,18 +119,20 @@ int main(int argc, char** argv) avnd::init_controls(object); // Create an audio processor -#if __has_include() +#if AVND_STANDALONE_AUDIO standalone::audio_mapper audio{ object, in_channels, out_channels, buffer_size, sample_rate}; +#endif +#if AVND_STANDALONE_OSCQUERY // Create an oscquery interface to it. - standalone::oscquery_mapper oscq{object, osc_port, ws_port}; + standalone::oscquery_mapper oscq{object, app_name, osc_port, ws_port}; std::thread t{[&] { oscq.run(); }}; #endif run_ui(object); -#if __has_include() +#if AVND_STANDALONE_OSCQUERY oscq.stop(); t.join(); #endif diff --git a/include/avnd/binding/standalone/standalone.hpp b/include/avnd/binding/standalone/standalone.hpp index c90517d5..a9749442 100644 --- a/include/avnd/binding/standalone/standalone.hpp +++ b/include/avnd/binding/standalone/standalone.hpp @@ -2,13 +2,15 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ -#if __has_include() +#if __has_include() #include +#define AVND_STANDALONE_AUDIO 1 +#endif + #if __has_include() #define AVND_STANDALONE_OSCQUERY 1 #include #endif -#endif #if __has_include() && __has_include() #define AVND_STANDALONE_QML 1 diff --git a/include/avnd/binding/ui/qml/enum_control.hpp b/include/avnd/binding/ui/qml/enum_control.hpp index ebd1705b..578fdccb 100644 --- a/include/avnd/binding/ui/qml/enum_control.hpp +++ b/include/avnd/binding/ui/qml/enum_control.hpp @@ -18,13 +18,17 @@ struct enum_control { using T = typename Parent::type; avnd::parameter_input_introspection::for_nth_raw( - avnd::get_inputs(parent.implementation), idx, [value](C& ctl) { - if constexpr(avnd::enum_parameter) - ctl.value = static_cast(value); + avnd::get_inputs(parent.implementation), idx, + [&parent, value](C& ctl) { + if constexpr(avnd::enum_parameter) + { + ctl.value = static_cast(value); + if_possible(ctl.update(parent.implementation)); + } }); } - template + template void create(Parent& parent, C& c, int control_k) { std::string_view name = value_if_possible(C::name(), else, "Control"); @@ -32,12 +36,26 @@ struct enum_control // Concat enumerator texts std::string enumerators; - enumerators.reserve(16 * avnd::get_enum_choices_count()); - for(std::string_view e : avnd::get_enum_choices()) + if constexpr(avnd::enum_parameter) { - enumerators += '"'; - enumerators += e; - enumerators += "\", "; + enumerators.reserve(16 * avnd::get_enum_choices_count()); + for(std::string_view e : avnd::get_enum_choices()) + { + enumerators += '"'; + enumerators += e; + enumerators += "\", "; + } + } + else + { + static constexpr auto range = avnd::get_range(); + enumerators.reserve(16 * std::size(range.values)); + for(const auto& [key, value] : range.values) + { + enumerators += '"'; + enumerators += key; + enumerators += "\", "; + } } // Remove last , diff --git a/include/avnd/binding/ui/qml/enum_ui.hpp b/include/avnd/binding/ui/qml/enum_ui.hpp index 8096c4d6..f226586e 100644 --- a/include/avnd/binding/ui/qml/enum_ui.hpp +++ b/include/avnd/binding/ui/qml/enum_ui.hpp @@ -7,7 +7,7 @@ ColumnLayout {{ objectName: "control_{0}" model: [ {1} ] currentIndex: {2} - Layout.maximumWidth: 80 + Layout.maximumWidth: 100 Layout.maximumHeight: 80 onCurrentIndexChanged: _uiHandler.enumChanged({0}, currentIndex) Layout.alignment: Qt.AlignHCenter @@ -18,7 +18,6 @@ ColumnLayout {{ Layout.alignment: Qt.AlignHCenter Layout.maximumWidth: 80 Layout.minimumWidth: 80 - color: "black" }} Layout.maximumHeight: 100 Layout.maximumWidth: 100 diff --git a/include/avnd/binding/ui/qml/float_control.hpp b/include/avnd/binding/ui/qml/float_control.hpp index ce7f764e..5d69b985 100644 --- a/include/avnd/binding/ui/qml/float_control.hpp +++ b/include/avnd/binding/ui/qml/float_control.hpp @@ -19,9 +19,13 @@ struct float_control { using T = typename Parent::type; avnd::parameter_input_introspection::for_nth_raw( - avnd::get_inputs(parent.implementation), idx, [value](C& ctl) { - if constexpr(avnd::float_parameter) - ctl.value = value; + avnd::get_inputs(parent.implementation), idx, + [&parent, value](C& ctl) { + if constexpr(avnd::float_parameter) + { + ctl.value = value; + if_possible(ctl.update(parent.implementation)); + } }); } @@ -32,6 +36,7 @@ struct float_control } template + requires(!avnd::enum_ish_parameter) void create(Parent& parent, C& c, int control_k) { std::string_view name = value_if_possible(C::name(), else, "Control"); diff --git a/include/avnd/binding/ui/qml/float_knob.hpp b/include/avnd/binding/ui/qml/float_knob.hpp index b61b9d2a..714da0e2 100644 --- a/include/avnd/binding/ui/qml/float_knob.hpp +++ b/include/avnd/binding/ui/qml/float_knob.hpp @@ -20,7 +20,6 @@ ColumnLayout {{ Layout.alignment: Qt.AlignHCenter Layout.maximumWidth: 80 Layout.minimumWidth: 80 - color: "black" }} Layout.maximumHeight: 100 Layout.maximumWidth: 100 diff --git a/include/avnd/binding/ui/qml/float_slider.hpp b/include/avnd/binding/ui/qml/float_slider.hpp index 86fba64f..34b27424 100644 --- a/include/avnd/binding/ui/qml/float_slider.hpp +++ b/include/avnd/binding/ui/qml/float_slider.hpp @@ -17,7 +17,6 @@ ColumnLayout {{ text: "{5}: " + _uiHandler.floatDisplay({0}, control_{0}.value) horizontalAlignment: Text.AlignHCenter Layout.alignment: Qt.AlignHCenter - color: "black" }} Layout.maximumHeight: 100 Layout.alignment: Qt.AlignVCenter diff --git a/include/avnd/binding/ui/qml/int_control.hpp b/include/avnd/binding/ui/qml/int_control.hpp index b75f98c5..e5a68e1b 100644 --- a/include/avnd/binding/ui/qml/int_control.hpp +++ b/include/avnd/binding/ui/qml/int_control.hpp @@ -17,9 +17,13 @@ struct int_control { using T = typename Parent::type; avnd::parameter_input_introspection::for_nth_raw( - avnd::get_inputs(parent.implementation), idx, [value](C& ctl) { - if constexpr(avnd::int_parameter) - ctl.value = value; + avnd::get_inputs(parent.implementation), idx, + [&parent, value](C& ctl) { + if constexpr(avnd::int_parameter) + { + ctl.value = value; + if_possible(ctl.update(parent.implementation)); + } }); } @@ -30,6 +34,7 @@ struct int_control } template + requires(!avnd::enum_ish_parameter) void create(Parent& parent, C& c, int control_k) { std::string_view name = value_if_possible(C::name(), else, "Control"); diff --git a/include/avnd/binding/ui/qml/int_knob.hpp b/include/avnd/binding/ui/qml/int_knob.hpp index fb99d170..f77d1024 100644 --- a/include/avnd/binding/ui/qml/int_knob.hpp +++ b/include/avnd/binding/ui/qml/int_knob.hpp @@ -20,7 +20,6 @@ ColumnLayout {{ text: "{5}: " + _uiHandler.intDisplay({0}, control_{0}.value) horizontalAlignment: Text.AlignHCenter Layout.alignment: Qt.AlignHCenter - color: "black" }} Layout.maximumHeight: 100 Layout.alignment: Qt.AlignVCenter diff --git a/include/avnd/binding/ui/qml/int_slider.hpp b/include/avnd/binding/ui/qml/int_slider.hpp index 4e3f6df7..3295f828 100644 --- a/include/avnd/binding/ui/qml/int_slider.hpp +++ b/include/avnd/binding/ui/qml/int_slider.hpp @@ -18,7 +18,6 @@ ColumnLayout {{ text: "{5}\n" + _uiHandler.intDisplay({0}, control_{0}.value) horizontalAlignment: Text.AlignHCenter Layout.alignment: Qt.AlignHCenter - color: "black" }} Layout.maximumHeight: 100 Layout.alignment: Qt.AlignVCenter diff --git a/include/avnd/binding/ui/qml/toggle_control.hpp b/include/avnd/binding/ui/qml/toggle_control.hpp index 841eab78..93de6765 100644 --- a/include/avnd/binding/ui/qml/toggle_control.hpp +++ b/include/avnd/binding/ui/qml/toggle_control.hpp @@ -18,13 +18,24 @@ struct toggle_control { using T = typename Parent::type; avnd::parameter_input_introspection::for_nth_raw( - avnd::get_inputs(parent.implementation), idx, [value](C& ctl) { - if constexpr(avnd::enum_parameter) - ctl.value = static_cast(value); + avnd::get_inputs(parent.implementation), idx, + [&parent, value](C& ctl) { + if constexpr(avnd::bool_parameter) + { + ctl.value = static_cast(value); + if_possible(ctl.update(parent.implementation)); + } }); } + template + QString display(Parent& parent, int idx, bool value) + { + return parent.toggle_display(idx, value); + } + template + requires(!avnd::enum_ish_parameter) void create(Parent& parent, C& c, int control_k) { std::string_view name = value_if_possible(C::name(), else, "Control"); diff --git a/include/avnd/binding/ui/qml/toggle_ui.hpp b/include/avnd/binding/ui/qml/toggle_ui.hpp index 942570ca..5400cd51 100644 --- a/include/avnd/binding/ui/qml/toggle_ui.hpp +++ b/include/avnd/binding/ui/qml/toggle_ui.hpp @@ -2,18 +2,18 @@ R"_( ColumnLayout {{ - CheckBox {{ + Switch {{ id: control_{0} objectName: "control_{0}" - checkState: {1} ? Qt.Checked : Qt.Unchecked - text: "{2}" - Layout.maximumWidth: 200 - Layout.maximumHeight: 40 - onCheckStateChanged: _uiHandler.toggleChanged({0}, checkState == Qt.Checked) + checked: {1} + onCheckedChanged: _uiHandler.toggleChanged({0}, checked) + Layout.alignment: Qt.AlignHCenter + }} + Label {{ + text: "{2}\n" + _uiHandler.toggleDisplay({0}, control_{0}.checked) + horizontalAlignment: Text.AlignHCenter Layout.alignment: Qt.AlignHCenter }} - Layout.maximumHeight: 40 - Layout.maximumWidth: 220 Layout.alignment: Qt.AlignVCenter }} )_" diff --git a/include/avnd/binding/ui/qml_layout_ui.hpp b/include/avnd/binding/ui/qml_layout_ui.hpp index fb8c44a2..7ec8ee2d 100644 --- a/include/avnd/binding/ui/qml_layout_ui.hpp +++ b/include/avnd/binding/ui/qml_layout_ui.hpp @@ -72,6 +72,23 @@ class qml_layout_ui_base return res; } + + QString toggle_display(int idx, bool value) + { + QString res; + + avnd::parameter_input_introspection::for_nth_raw( + avnd::get_inputs(implementation), idx, [&res, value](C& ctl) { + char buf[128] = {0}; + if constexpr(requires { ctl.display(buf, value); }) + { + ctl.display(buf, value); + res = QString::fromUtf8(buf); + } + }); + + return res; + } }; template @@ -102,10 +119,10 @@ class qml_layout_ui /// Here we generate a QML file content // The header - append(R"_(import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuick.Controls 2.15 -ApplicationWindow {{ + append(R"_(import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +Window {{ visible: true Item {{ objectName: "mainItem"; anchors.fill: parent @@ -144,7 +161,7 @@ ApplicationWindow {{ if constexpr(requires { { item - } -> std::convertible_to; + } -> std::convertible_to; }) { append( @@ -268,6 +285,11 @@ ApplicationWindow {{ toggle_control::changed(*this, idx, value); } W_SLOT(toggleChanged, (int, bool)) + QString toggleDisplay(int idx, bool value) noexcept + { + return toggle_control::display(*this, idx, value); + } + W_SLOT(toggleDisplay, (int, bool)) }; } diff --git a/include/avnd/binding/ui/qml_ui.hpp b/include/avnd/binding/ui/qml_ui.hpp index 0ecf3ae3..0b901341 100644 --- a/include/avnd/binding/ui/qml_ui.hpp +++ b/include/avnd/binding/ui/qml_ui.hpp @@ -72,6 +72,23 @@ class qml_ui_base return res; } + + QString toggle_display(int idx, bool value) + { + QString res; + + avnd::parameter_input_introspection::for_nth_raw( + avnd::get_inputs(implementation), idx, [&res, value](C& ctl) { + char buf[128] = {0}; + if constexpr(requires { ctl.display(buf, value); }) + { + ctl.display(buf, value); + res = QString::fromUtf8(buf); + } + }); + + return res; + } }; template @@ -103,19 +120,20 @@ class qml_ui // The header fmt::format_to( std::back_inserter(this->componentData), - R"_(import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuick.Controls 2.15 + R"_(import QtQuick +import QtQuick.Layouts +import QtQuick.Controls -Item {{ +Pane {{ + anchors.fill: parent ColumnLayout {{ - Text {{ + Label {{ text: "{}" }} RowLayout {{ )_", - T::name()); + avnd::get_name()); // The controls int control_k = 0; @@ -178,6 +196,11 @@ Item {{ toggle_control::changed(*this, idx, value); } W_SLOT(toggleChanged, (int, bool)) + QString toggleDisplay(int idx, bool value) noexcept + { + return toggle_control::display(*this, idx, value); + } + W_SLOT(toggleDisplay, (int, bool)) }; } diff --git a/include/avnd/binding/vst3/controller.hpp b/include/avnd/binding/vst3/controller.hpp index b09fbd3e..04fb71e5 100644 --- a/include/avnd/binding/vst3/controller.hpp +++ b/include/avnd/binding/vst3/controller.hpp @@ -14,6 +14,9 @@ #include +#if defined(AVND_ADD_OSCQUERY_BINDINGS) +#include +#endif namespace stv3 { template @@ -60,12 +63,22 @@ class Controller final using inputs_t = typename avnd::inputs_type::type; inputs_t inputs_mirror{}; +#undef AVND_ADD_OSCQUERY_BINDINGS +#if AVND_ADD_OSCQUERY_BINDINGS + standalone::oscquery_minimal_mapper oscquery_mapper{ + std::string(avnd::get_name()), 1234, 5678}; +#endif using inputs_info_t = avnd::parameter_input_introspection; static const constexpr int32_t parameter_count = inputs_info_t::size; public: - Controller() { } + Controller() + { +#if AVND_ADD_OSCQUERY_BINDINGS + oscquery_mapper.create_ports(inputs_mirror); +#endif + } virtual ~Controller(); @@ -170,7 +183,6 @@ class Controller final { bool ok = inputs_info_t::for_all_unless( this->inputs_mirror, [&](C& field) -> bool { - double param = 0.f; if(streamer.readDouble(param) == false) return false; diff --git a/include/avnd/binding/vst3/helpers.hpp b/include/avnd/binding/vst3/helpers.hpp index 5c15d300..f6a4fa34 100644 --- a/include/avnd/binding/vst3/helpers.hpp +++ b/include/avnd/binding/vst3/helpers.hpp @@ -21,6 +21,7 @@ template auto setStr(TChar (&field)[M], std::wstring_view text) { std::copy_n(text.data(), text.size(), field); + field[text.size()] = 0; } #else #define u16 u"" @@ -28,6 +29,7 @@ template auto setStr(TChar (&field)[M], std::u16string_view text) { std::copy_n(text.data(), text.size(), field); + field[text.size()] = 0; } #endif @@ -35,6 +37,7 @@ template auto setStr(TChar (&field)[M], std::string_view text) { avnd::utf8_to_utf16(text.data(), text.data() + text.size(), field); + field[text.size()] = 0; } inline Steinberg::tresult isProjectState(Steinberg::IBStream* state) @@ -56,7 +59,7 @@ inline Steinberg::tresult isProjectState(Steinberg::IBStream* state) == kResultTrue) { UString128 tmp(string); - char ascii[128]; + char ascii[128] = {}; tmp.toAscii(ascii, 128); if(!strncmp(ascii, StateType::kProject, strlen(StateType::kProject))) { diff --git a/include/avnd/binding/vst3/prototype.cpp.in b/include/avnd/binding/vst3/prototype.cpp.in index e3d154ae..6e271b2a 100644 --- a/include/avnd/binding/vst3/prototype.cpp.in +++ b/include/avnd/binding/vst3/prototype.cpp.in @@ -1,27 +1,31 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ -#include <@AVND_MAIN_FILE@> - #include #include - #include +// clang-format off +#include <@AVND_MAIN_FILE@> -bool InitModule () -{ - return true; -} - -bool DeinitModule () -{ - return true; -} - -extern "C" -AVND_EXPORTED_SYMBOL Steinberg::IPluginFactory* GetPluginFactory() +// Needed everywhere +bool InitModule() { return true; } +bool DeinitModule() { return true; } +#if __APPLE__ +extern "C" AVND_EXPORTED_SYMBOL bool BundleEntry() { return true; } +extern "C" AVND_EXPORTED_SYMBOL bool BundleExit() { return true; } +extern "C" AVND_EXPORTED_SYMBOL bool bundleEntry() { return true; } +extern "C" AVND_EXPORTED_SYMBOL bool bundleExit() { return true; } +#elif _WIN32 +extern "C" AVND_EXPORTED_SYMBOL bool InitDll() { return true; } +extern "C" AVND_EXPORTED_SYMBOL bool ExitDll() { return true; } +#elif __linux__ +extern "C" AVND_EXPORTED_SYMBOL bool ModuleEntry() { return true; } +extern "C" AVND_EXPORTED_SYMBOL bool ModuleExit() { return true; } +#endif + +extern "C" AVND_EXPORTED_SYMBOL Steinberg::IPluginFactory* GetPluginFactory() { - using type = decltype(avnd::configure())::type; + using type = decltype(avnd::configure())::type; // return new stv3::factory{}; using component_t = stv3::Component; @@ -29,64 +33,66 @@ AVND_EXPORTED_SYMBOL Steinberg::IPluginFactory* GetPluginFactory() static stv3::factory fact; return &fact; } - -namespace Steinberg { -namespace Vst { +// clang-format on +namespace Steinberg +{ +namespace Vst +{ //----VST 3.0-------------------------------- -DEF_CLASS_IID (IComponent) -DEF_CLASS_IID (IAudioProcessor) -DEF_CLASS_IID (IUnitData) -DEF_CLASS_IID (IProgramListData) +DEF_CLASS_IID(IComponent) +DEF_CLASS_IID(IAudioProcessor) +DEF_CLASS_IID(IUnitData) +DEF_CLASS_IID(IProgramListData) -DEF_CLASS_IID (IEditController) -DEF_CLASS_IID (IUnitInfo) +DEF_CLASS_IID(IEditController) +DEF_CLASS_IID(IUnitInfo) -DEF_CLASS_IID (IConnectionPoint) +DEF_CLASS_IID(IConnectionPoint) -DEF_CLASS_IID (IComponentHandler) -DEF_CLASS_IID (IUnitHandler) +DEF_CLASS_IID(IComponentHandler) +DEF_CLASS_IID(IUnitHandler) -DEF_CLASS_IID (IParamValueQueue) -DEF_CLASS_IID (IParameterChanges) +DEF_CLASS_IID(IParamValueQueue) +DEF_CLASS_IID(IParameterChanges) -DEF_CLASS_IID (IEventList) -DEF_CLASS_IID (IMessage) +DEF_CLASS_IID(IEventList) +DEF_CLASS_IID(IMessage) -DEF_CLASS_IID (IHostApplication) -DEF_CLASS_IID (IAttributeList) +DEF_CLASS_IID(IHostApplication) +DEF_CLASS_IID(IAttributeList) //----VST 3.0.1-------------------------------- -DEF_CLASS_IID (IMidiMapping) +DEF_CLASS_IID(IMidiMapping) //----VST 3.0.2-------------------------------- //----VST 3.1---------------------------------- -DEF_CLASS_IID (IComponentHandler2) -DEF_CLASS_IID (IEditController2) -DEF_CLASS_IID (IAudioPresentationLatency) -DEF_CLASS_IID (IVst3ToVst2Wrapper) -DEF_CLASS_IID (IVst3ToAUWrapper) +DEF_CLASS_IID(IComponentHandler2) +DEF_CLASS_IID(IEditController2) +DEF_CLASS_IID(IAudioPresentationLatency) +DEF_CLASS_IID(IVst3ToVst2Wrapper) +DEF_CLASS_IID(IVst3ToAUWrapper) //----VST 3.5---------------------------------- -DEF_CLASS_IID (INoteExpressionController) -DEF_CLASS_IID (IKeyswitchController) -DEF_CLASS_IID (IEditControllerHostEditing) +DEF_CLASS_IID(INoteExpressionController) +DEF_CLASS_IID(IKeyswitchController) +DEF_CLASS_IID(IEditControllerHostEditing) //----VST 3.6---------------------------------- -DEF_CLASS_IID (IStreamAttributes) +DEF_CLASS_IID(IStreamAttributes) //----VST 3.6.5-------------------------------- -DEF_CLASS_IID (IUnitHandler2) +DEF_CLASS_IID(IUnitHandler2) //----VST 3.6.8-------------------------------- -DEF_CLASS_IID (IComponentHandlerBusActivation) -DEF_CLASS_IID (IVst3ToAAXWrapper) - -DEF_CLASS_IID (IVst3WrapperMPESupport) +DEF_CLASS_IID(IComponentHandlerBusActivation) +DEF_CLASS_IID(IVst3ToAAXWrapper) +DEF_CLASS_IID(IVst3WrapperMPESupport) //----VST 3.7----------------------------------- -DEF_CLASS_IID (IProcessContextRequirements) -DEF_CLASS_IID (IProgress) -}} +DEF_CLASS_IID(IProcessContextRequirements) +DEF_CLASS_IID(IProgress) +} +} diff --git a/include/avnd/introspection/widgets.hpp b/include/avnd/introspection/widgets.hpp index 174470df..981e09d4 100644 --- a/include/avnd/introspection/widgets.hpp +++ b/include/avnd/introspection/widgets.hpp @@ -7,8 +7,10 @@ #include #include +#include #include #include +#include namespace avnd { @@ -19,48 +21,40 @@ template static constexpr std::array to_string_view_array(const char* const (&a)[N]) { - return [&](std::index_sequence) - ->std::array - { + return [&]( + std::index_sequence) -> std::array { return {{a[I]...}}; - } - (std::make_index_sequence{}); + }(std::make_index_sequence{}); } template static constexpr std::array to_string_view_array(const std::string_view (&a)[N]) { - return [&](std::index_sequence) - ->std::array - { + return [&]( + std::index_sequence) -> std::array { return {{a[I]...}}; - } - (std::make_index_sequence{}); + }(std::make_index_sequence{}); } template static constexpr std::array to_string_view_array(const std::array& a) { - return [&](std::index_sequence) - ->std::array - { + return [&]( + std::index_sequence) -> std::array { return {{a[I]...}}; - } - (std::make_index_sequence{}); + }(std::make_index_sequence{}); } template static constexpr std::array to_string_view_array(const std::pair (&a)[N]) { - return [&](std::index_sequence) - ->std::array - { + return [&]( + std::index_sequence) -> std::array { return {{a[I].first...}}; - } - (std::make_index_sequence{}); + }(std::make_index_sequence{}); } template @@ -103,4 +97,56 @@ consteval auto get_enum_choices() return std::array{}; } } + +template +constexpr auto to_const_char_array(const T (&val)[N]) +{ + //using pair_type = typename std::decay_t::value_type; + using value_type = std::decay_t; + + std::array, N> choices_cstr; + for(int i = 0; i < N; i++) + { + choices_cstr[i].first = val[i].first.data(); + choices_cstr[i].second = val[i].second; + } + return choices_cstr; +} + +template +constexpr auto +to_const_char_array(const std::array, N>& val) +{ + std::array choices_cstr; + for(int i = 0; i < N; i++) + choices_cstr[i] = val[i].data(); + return choices_cstr; +} + +template +constexpr auto to_const_char_array(const std::string_view (&val)[N]) +{ + std::array choices_cstr; + for(int i = 0; i < N; i++) + choices_cstr[i] = val[i].data(); + return choices_cstr; +} + +template +constexpr auto to_const_char_array(const std::array& val) +{ + std::array choices_cstr; + for(int i = 0; i < N; i++) + choices_cstr[i] = val[i].data(); + return choices_cstr; +} + +std::vector to_enum_range(const auto& in) +{ + std::vector vec; + for(auto& v : to_const_char_array(in)) + vec.emplace_back(v); + return vec; +} + } diff --git a/include/avnd/wrappers/metadatas.hpp b/include/avnd/wrappers/metadatas.hpp index 20ab4769..3195a6e8 100644 --- a/include/avnd/wrappers/metadatas.hpp +++ b/include/avnd/wrappers/metadatas.hpp @@ -124,6 +124,13 @@ define_get_property(description, std::string_view, "(description)") define_get_property(short_description, std::string_view, "(module)") define_get_property(module, std::string_view, "(module)") +template +constexpr std::string_view default_osc_path() +{ + return get_name(); +} +define_get_property(path, std::string_view, default_osc_path()) + // FIXME: C++23: constexpr ? std::string array_to_string(auto& authors) {