diff --git a/examples/Raw/Aggregate.hpp b/examples/Raw/Aggregate.hpp index 7aba7e6a..5eb0ab82 100644 --- a/examples/Raw/Aggregate.hpp +++ b/examples/Raw/Aggregate.hpp @@ -13,6 +13,13 @@ namespace examples { /** * This example showcases using user-defined aggregates for value ports. + * + * Note that it only makes sense in environments that support hierarchic data structures: + * - ossia + * - Max/MSP with a dict as input + * - programming languages like Python + * + * For instance, it does not make sense in PureData or audio plugins */ struct Aggregate { diff --git a/include/avnd/binding/pd/audio_processor.hpp b/include/avnd/binding/pd/audio_processor.hpp index 6e092670..88391b33 100644 --- a/include/avnd/binding/pd/audio_processor.hpp +++ b/include/avnd/binding/pd/audio_processor.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -58,6 +59,7 @@ struct audio_processor avnd::process_adapter processor; std::array dsp_inputs; + inputs input_setup; [[no_unique_address]] init_arguments init_setup; [[no_unique_address]] messages messages_setup; @@ -84,6 +86,8 @@ struct audio_processor for(int i = 0; i < output_channels; i++) outlet_new(&x_obj, &s_signal); + // control_inputs is *not* initialized here, all the messages will go through 1st inlet. + /// Initialize controls if constexpr(avnd::has_inputs) { @@ -160,61 +164,13 @@ struct audio_processor return ++w; } - void process_inlet_control(t_symbol* s, int argc, t_atom* argv) - { - for(auto state : implementation.full_state()) - { - switch(argv[0].a_type) - { - case A_FLOAT: { - // Note: teeeechnically, one could store a map of string -> {void*,typeid} and then cast... - // but most pd externals seem to just do a chain of if() so this is equivalent - float res = argv[0].a_w.w_float; - avnd::for_each_field_ref(state.inputs, [s, res, &state](C& ctl) { - if constexpr( - avnd::float_parameter || avnd::int_parameter - || avnd::bool_parameter) - { - static constexpr auto control_name = pd::get_name_symbol(); - if(control_name == s->s_name) - { - avnd::apply_control(ctl, res); - if_possible(ctl.update(state.effect)); - } - } - }); - break; - } - - case A_SYMBOL: { - // TODO ? - std::string_view res = argv[0].a_w.w_symbol->s_name; - // thread_local for perf ? - avnd::for_each_field_ref(state.inputs, [s, &res, &state](C& ctl) { - if constexpr(avnd::string_parameter) - { - static constexpr auto control_name = pd::get_name_symbol(); - if(control_name == s->s_name) - { - avnd::apply_control(ctl, std::move(res)); - if_possible(ctl.update(state.effect)); - } - } - }); - break; - } - - default: - break; - } - } - } - void process(t_symbol* s, int argc, t_atom* argv) { // First try to process messages handled explicitely in the object if(messages_setup.process_messages(implementation, s, argc, argv)) return; + if(input_setup.process_inputs(implementation, s, argc, argv)) + return; // Then some default behaviour switch(argc) @@ -237,7 +193,7 @@ struct audio_processor } default: { // Apply the data to the inlets. - process_inlet_control(s, argc, argv); + // process_inlet_control(s, argc, argv); // -> done in input_setup.process_inputs // Then bang // output_setup.commit(implementation); diff --git a/include/avnd/binding/pd/inputs.hpp b/include/avnd/binding/pd/inputs.hpp index 67a79d3b..8f66fc3b 100644 --- a/include/avnd/binding/pd/inputs.hpp +++ b/include/avnd/binding/pd/inputs.hpp @@ -371,6 +371,19 @@ struct inputs return true; } } + else + { + static std::once_flag f; + std::call_once(f, [] { + post("Field type not supported as input: %s", +#if defined(_MSC_VER) + __FUNCSIG__ +#else + __PRETTY_FUNCTION__ +#endif + ); + }); + } return false; } @@ -382,15 +395,19 @@ struct inputs { bool ok = false; std::string_view symname = s->s_name; - avnd::parameter_input_introspection::for_all( - avnd::get_inputs(implementation), [&](M& field) { - if(ok) - return; - if(symname == pd::get_name_symbol()) - { - ok = process_inlet_control(implementation.effect, field, argc, argv); - } - }); + + for(auto state : implementation.full_state()) + { + avnd::parameter_input_introspection::for_all( + state.inputs, [&,&obj=state.effect](M& field) { + if(ok) + return; + if(symname == pd::get_name_symbol()) + { + ok = process_inlet_control(obj, field, argc, argv); + } + }); + } return ok; } return false; diff --git a/include/avnd/binding/pd/message_processor.hpp b/include/avnd/binding/pd/message_processor.hpp index 38cd39b9..5a9592ca 100644 --- a/include/avnd/binding/pd/message_processor.hpp +++ b/include/avnd/binding/pd/message_processor.hpp @@ -164,7 +164,6 @@ struct message_processor void process(t_symbol* s, int argc, t_atom* argv) { - // First try to process messages handled explicitely in the object if(messages_setup.process_messages(implementation, s, argc, argv)) return;