From 1d6207428fb801908bf38f7628aeccbb4ca8a384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Wed, 27 Sep 2023 08:22:09 -0400 Subject: [PATCH] [standalone] Improvements, support for audio --- cmake/avendish.cmake | 119 +++++++++++++++++- cmake/avendish.examples.cmake | 7 ++ cmake/avendish.ossia.cmake | 3 +- cmake/avendish.sources.cmake | 106 +--------------- cmake/avendish.standalone.cmake | 5 +- examples/Raw/Sines.hpp | 9 +- include/avnd/binding/standalone/audio.hpp | 74 +++++++++++ .../binding/standalone/oscquery_mapper.hpp | 40 ++---- .../avnd/binding/standalone/prototype.cpp.in | 103 ++++++++++++--- .../avnd/binding/standalone/standalone.hpp | 1 + include/avnd/concepts/processor.hpp | 6 +- include/avnd/wrappers/process_execution.hpp | 57 +++++++++ include/avnd/wrappers/smooth.hpp | 3 +- 13 files changed, 368 insertions(+), 165 deletions(-) diff --git a/cmake/avendish.cmake b/cmake/avendish.cmake index 0dfaee31..92b5b6b8 100644 --- a/cmake/avendish.cmake +++ b/cmake/avendish.cmake @@ -10,6 +10,114 @@ find_package(Boost QUIET REQUIRED) find_package(Threads QUIET) find_package(fmt QUIET) + +set(AVENDISH_SOURCES + "${AVND_SOURCE_DIR}/include/avnd/concepts/all.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/attributes.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/audio_port.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/audio_processor.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/callback.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/channels.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/fft.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/generic.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/gfx.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/layout.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/message.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/midi.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/midi_port.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/modules.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/object.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/painter.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/parameter.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/port.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/processor.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/schedule.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/soundfile.hpp" + "${AVND_SOURCE_DIR}/include/avnd/concepts/synth.hpp" + + "${AVND_SOURCE_DIR}/include/avnd/introspection/channels.hpp" + "${AVND_SOURCE_DIR}/include/avnd/introspection/input.hpp" + "${AVND_SOURCE_DIR}/include/avnd/introspection/messages.hpp" + "${AVND_SOURCE_DIR}/include/avnd/introspection/midi.hpp" + "${AVND_SOURCE_DIR}/include/avnd/introspection/modules.hpp" + "${AVND_SOURCE_DIR}/include/avnd/introspection/output.hpp" + "${AVND_SOURCE_DIR}/include/avnd/introspection/port.hpp" + "${AVND_SOURCE_DIR}/include/avnd/introspection/widgets.hpp" + + "${AVND_SOURCE_DIR}/include/avnd/wrappers/audio_channel_manager.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/avnd.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/bus_host_process_adapter.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/configure.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/control_display.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/controls.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/controls_double.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/controls_fp.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/controls_storage.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/effect_container.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/metadatas.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/prepare.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/process_adapter.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/process_execution.hpp" + "${AVND_SOURCE_DIR}/include/avnd/wrappers/widgets.hpp" + + "${AVND_SOURCE_DIR}/include/avnd/common/aggregates.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/concepts_polyfill.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/coroutines.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/dummy.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/errors.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/export.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/for_nth.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/function_reflection.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/index_sequence.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/limited_string.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/limited_string_view.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/span_polyfill.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/struct_reflection.hpp" + "${AVND_SOURCE_DIR}/include/avnd/common/widechar.hpp" + + "${AVND_SOURCE_DIR}/include/halp/attributes.hpp" + "${AVND_SOURCE_DIR}/include/halp/audio.hpp" + "${AVND_SOURCE_DIR}/include/halp/callback.hpp" + "${AVND_SOURCE_DIR}/include/halp/compat/gamma.hpp" + "${AVND_SOURCE_DIR}/include/halp/controls.basic.hpp" + "${AVND_SOURCE_DIR}/include/halp/controls.buttons.hpp" + "${AVND_SOURCE_DIR}/include/halp/controls.enums.hpp" + "${AVND_SOURCE_DIR}/include/halp/controls.hpp" + "${AVND_SOURCE_DIR}/include/halp/controls.sliders.gcc10.hpp" + "${AVND_SOURCE_DIR}/include/halp/controls.sliders.hpp" + "${AVND_SOURCE_DIR}/include/halp/controls.typedefs.hpp" + "${AVND_SOURCE_DIR}/include/halp/controls_fmt.hpp" + "${AVND_SOURCE_DIR}/include/halp/curve.hpp" + "${AVND_SOURCE_DIR}/include/halp/custom_widgets.hpp" + "${AVND_SOURCE_DIR}/include/halp/fft.hpp" + "${AVND_SOURCE_DIR}/include/halp/file_port.hpp" + "${AVND_SOURCE_DIR}/include/halp/geometry.hpp" + "${AVND_SOURCE_DIR}/include/halp/gradient_port.hpp" + "${AVND_SOURCE_DIR}/include/halp/inline.hpp" + "${AVND_SOURCE_DIR}/include/halp/layout.hpp" + "${AVND_SOURCE_DIR}/include/halp/log.hpp" + "${AVND_SOURCE_DIR}/include/halp/mappers.hpp" + "${AVND_SOURCE_DIR}/include/halp/messages.hpp" + "${AVND_SOURCE_DIR}/include/halp/meta.hpp" + "${AVND_SOURCE_DIR}/include/halp/midi.hpp" + "${AVND_SOURCE_DIR}/include/halp/midifile_port.hpp" + "${AVND_SOURCE_DIR}/include/halp/polyfill.hpp" + "${AVND_SOURCE_DIR}/include/halp/reactive_value.hpp" + "${AVND_SOURCE_DIR}/include/halp/sample_accurate_controls.hpp" + "${AVND_SOURCE_DIR}/include/halp/schedule.hpp" + "${AVND_SOURCE_DIR}/include/halp/smoothers.hpp" + "${AVND_SOURCE_DIR}/include/halp/soundfile_port.hpp" + "${AVND_SOURCE_DIR}/include/halp/static_string.hpp" + "${AVND_SOURCE_DIR}/include/halp/texture.hpp" + "${AVND_SOURCE_DIR}/include/halp/texture_formats.hpp" + "${AVND_SOURCE_DIR}/include/halp/value_types.hpp" + + "${AVND_SOURCE_DIR}/include/gpp/commands.hpp" + "${AVND_SOURCE_DIR}/include/gpp/generators.hpp" + "${AVND_SOURCE_DIR}/include/gpp/meta.hpp" + "${AVND_SOURCE_DIR}/include/gpp/layout.hpp" +) + include(avendish.disableexceptions) include(avendish.sources) @@ -26,8 +134,17 @@ include(avendish.example) # Used for getting completion in IDEs... function(avnd_register) - cmake_parse_arguments(AVND "" "TARGET;MAIN_FILE;MAIN_CLASS;C_NAME" "" ${ARGN}) + cmake_parse_arguments(AVND "" "TARGET;MAIN_FILE;MAIN_CLASS;C_NAME;COMPILE_OPTIONS;COMPILE_DEFINITIONS;LINK_LIBRARIES" "" ${ARGN}) target_sources(Avendish PRIVATE "${AVND_MAIN_FILE}") + if(AVND_COMPILE_OPTIONS) + target_compile_options(Avendish PRIVATE "${AVND_COMPILE_OPTIONS}") + endif() + if(AVND_COMPILE_DEFINITIONS) + target_compile_definitions(Avendish PRIVATE "${AVND_COMPILE_DEFINITIONS}") + endif() + if(AVND_LINK_LIBRARIES) + target_link_libraries(Avendish PRIVATE "${AVND_LINK_LIBRARIES}") + endif() endfunction() # Bindings to programming languages, things with a proper object model diff --git a/cmake/avendish.examples.cmake b/cmake/avendish.examples.cmake index 461a2a7c..eb2fbac5 100644 --- a/cmake/avendish.examples.cmake +++ b/cmake/avendish.examples.cmake @@ -78,6 +78,13 @@ avnd_make_object( C_NAME avnd_init ) +avnd_make_all( + TARGET Sines + MAIN_FILE examples/Raw/Sines.hpp + MAIN_CLASS examples::Sine + C_NAME avnd_sines +) + avnd_make_object( TARGET Callback MAIN_FILE examples/Raw/Callback.hpp diff --git a/cmake/avendish.ossia.cmake b/cmake/avendish.ossia.cmake index 11964c6a..9d4b5f61 100644 --- a/cmake/avendish.ossia.cmake +++ b/cmake/avendish.ossia.cmake @@ -1,7 +1,8 @@ find_package(ossia QUIET) find_package(SDL2 QUIET) -if(NOT TARGET ossia::ossia) +if(1) +#if(NOT TARGET ossia::ossia) message(STATUS "libossia not found, skipping bindings...") function(avnd_make_ossia) diff --git a/cmake/avendish.sources.cmake b/cmake/avendish.sources.cmake index 842b43c8..420965ec 100644 --- a/cmake/avendish.sources.cmake +++ b/cmake/avendish.sources.cmake @@ -18,111 +18,7 @@ endif() target_sources(Avendish PUBLIC - "${AVND_SOURCE_DIR}/include/avnd/concepts/all.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/attributes.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/audio_port.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/audio_processor.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/callback.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/channels.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/fft.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/generic.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/gfx.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/layout.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/message.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/midi.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/midi_port.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/modules.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/object.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/painter.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/parameter.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/port.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/processor.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/schedule.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/soundfile.hpp" - "${AVND_SOURCE_DIR}/include/avnd/concepts/synth.hpp" - - "${AVND_SOURCE_DIR}/include/avnd/introspection/channels.hpp" - "${AVND_SOURCE_DIR}/include/avnd/introspection/input.hpp" - "${AVND_SOURCE_DIR}/include/avnd/introspection/messages.hpp" - "${AVND_SOURCE_DIR}/include/avnd/introspection/midi.hpp" - "${AVND_SOURCE_DIR}/include/avnd/introspection/modules.hpp" - "${AVND_SOURCE_DIR}/include/avnd/introspection/output.hpp" - "${AVND_SOURCE_DIR}/include/avnd/introspection/port.hpp" - "${AVND_SOURCE_DIR}/include/avnd/introspection/widgets.hpp" - - "${AVND_SOURCE_DIR}/include/avnd/wrappers/audio_channel_manager.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/avnd.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/bus_host_process_adapter.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/configure.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/control_display.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/controls.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/controls_double.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/controls_fp.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/controls_storage.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/effect_container.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/metadatas.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/prepare.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/process_adapter.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/process_execution.hpp" - "${AVND_SOURCE_DIR}/include/avnd/wrappers/widgets.hpp" - - "${AVND_SOURCE_DIR}/include/avnd/common/aggregates.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/concepts_polyfill.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/coroutines.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/dummy.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/errors.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/export.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/for_nth.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/function_reflection.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/index_sequence.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/limited_string.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/limited_string_view.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/span_polyfill.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/struct_reflection.hpp" - "${AVND_SOURCE_DIR}/include/avnd/common/widechar.hpp" - - "${AVND_SOURCE_DIR}/include/halp/attributes.hpp" - "${AVND_SOURCE_DIR}/include/halp/audio.hpp" - "${AVND_SOURCE_DIR}/include/halp/callback.hpp" - "${AVND_SOURCE_DIR}/include/halp/compat/gamma.hpp" - "${AVND_SOURCE_DIR}/include/halp/controls.basic.hpp" - "${AVND_SOURCE_DIR}/include/halp/controls.buttons.hpp" - "${AVND_SOURCE_DIR}/include/halp/controls.enums.hpp" - "${AVND_SOURCE_DIR}/include/halp/controls.hpp" - "${AVND_SOURCE_DIR}/include/halp/controls.sliders.gcc10.hpp" - "${AVND_SOURCE_DIR}/include/halp/controls.sliders.hpp" - "${AVND_SOURCE_DIR}/include/halp/controls.typedefs.hpp" - "${AVND_SOURCE_DIR}/include/halp/controls_fmt.hpp" - "${AVND_SOURCE_DIR}/include/halp/curve.hpp" - "${AVND_SOURCE_DIR}/include/halp/custom_widgets.hpp" - "${AVND_SOURCE_DIR}/include/halp/fft.hpp" - "${AVND_SOURCE_DIR}/include/halp/file_port.hpp" - "${AVND_SOURCE_DIR}/include/halp/geometry.hpp" - "${AVND_SOURCE_DIR}/include/halp/gradient_port.hpp" - "${AVND_SOURCE_DIR}/include/halp/inline.hpp" - "${AVND_SOURCE_DIR}/include/halp/layout.hpp" - "${AVND_SOURCE_DIR}/include/halp/log.hpp" - "${AVND_SOURCE_DIR}/include/halp/mappers.hpp" - "${AVND_SOURCE_DIR}/include/halp/messages.hpp" - "${AVND_SOURCE_DIR}/include/halp/meta.hpp" - "${AVND_SOURCE_DIR}/include/halp/midi.hpp" - "${AVND_SOURCE_DIR}/include/halp/midifile_port.hpp" - "${AVND_SOURCE_DIR}/include/halp/polyfill.hpp" - "${AVND_SOURCE_DIR}/include/halp/reactive_value.hpp" - "${AVND_SOURCE_DIR}/include/halp/sample_accurate_controls.hpp" - "${AVND_SOURCE_DIR}/include/halp/schedule.hpp" - "${AVND_SOURCE_DIR}/include/halp/smoothers.hpp" - "${AVND_SOURCE_DIR}/include/halp/soundfile_port.hpp" - "${AVND_SOURCE_DIR}/include/halp/static_string.hpp" - "${AVND_SOURCE_DIR}/include/halp/texture.hpp" - "${AVND_SOURCE_DIR}/include/halp/texture_formats.hpp" - "${AVND_SOURCE_DIR}/include/halp/value_types.hpp" - - "${AVND_SOURCE_DIR}/include/gpp/commands.hpp" - "${AVND_SOURCE_DIR}/include/gpp/generators.hpp" - "${AVND_SOURCE_DIR}/include/gpp/meta.hpp" - "${AVND_SOURCE_DIR}/include/gpp/layout.hpp" - + ${AVENDISH_SOURCES} "${AVND_SOURCE_DIR}/src/dummy.cpp" ) diff --git a/cmake/avendish.standalone.cmake b/cmake/avendish.standalone.cmake index 5b42e418..90a0a1ea 100644 --- a/cmake/avendish.standalone.cmake +++ b/cmake/avendish.standalone.cmake @@ -109,7 +109,7 @@ function(avnd_make_standalone) avnd_common_setup("${AVND_TARGET}" "${AVND_FX_TARGET}") - target_sources(Avendish PRIVATE + target_sources("${AVND_FX_TARGET}" PRIVATE "${AVND_SOURCE_DIR}/include/avnd/binding/standalone/audio.hpp" "${AVND_SOURCE_DIR}/include/avnd/binding/standalone/configure.hpp" "${AVND_SOURCE_DIR}/include/avnd/binding/standalone/standalone.hpp" @@ -139,6 +139,7 @@ function(avnd_make_standalone) target_sources( ${AVND_FX_TARGET} PRIVATE + ${AVENDISH_SOURCES} "${CMAKE_BINARY_DIR}/${MAIN_OUT_FILE}_standalone.cpp" ) @@ -167,7 +168,7 @@ function(avnd_make_standalone) avnd_common_setup("${AVND_TARGET}" "${AVND_FX_TARGET}") - target_sources(Avendish PRIVATE + target_sources(${AVND_FX_TARGET} PRIVATE "${AVND_SOURCE_DIR}/include/avnd/binding/standalone/audio.hpp" "${AVND_SOURCE_DIR}/include/avnd/binding/standalone/configure.hpp" "${AVND_SOURCE_DIR}/include/avnd/binding/standalone/standalone.hpp" diff --git a/examples/Raw/Sines.hpp b/examples/Raw/Sines.hpp index 45c798ef..dbfa2a8f 100644 --- a/examples/Raw/Sines.hpp +++ b/examples/Raw/Sines.hpp @@ -4,6 +4,7 @@ #include +#include #include #include @@ -96,10 +97,10 @@ struct Sine void operator()(const inputs& inputs, outputs& outputs) { const double phi[4] = { - 2 * 3.14 * inputs.f1.value / setup.rate, - 2 * 3.14 * inputs.f2.value / setup.rate, - 2 * 3.14 * inputs.f3.value / setup.rate, - 2 * 3.14 * inputs.f4.value / setup.rate, + 2. * std::numbers::pi * inputs.f1.value / setup.rate, + 2. * std::numbers::pi * inputs.f2.value / setup.rate, + 2. * std::numbers::pi * inputs.f3.value / setup.rate, + 2. * std::numbers::pi * inputs.f4.value / setup.rate, }; outputs.audio.sample = 0.; for(int i = 0; i < 4; i++) diff --git a/include/avnd/binding/standalone/audio.hpp b/include/avnd/binding/standalone/audio.hpp index e69de29b..c152e509 100644 --- a/include/avnd/binding/standalone/audio.hpp +++ b/include/avnd/binding/standalone/audio.hpp @@ -0,0 +1,74 @@ +#pragma once + +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace standalone +{ + +struct audio_tick +{ + int frames; +}; + +template +struct audio_mapper +{ + avnd::effect_container& object; + ossia::audio_engine* audio{}; + + [[no_unique_address]] avnd::process_adapter processor; + + explicit audio_mapper( + avnd::effect_container& object, int in_channels, int out_channels, int bs, + int rate) + : object{object} + { + int want_ins = avnd::input_channels(in_channels); + int want_outs = avnd::output_channels(out_channels); + + int want_buffer_size = bs; + int want_sample_rate = rate; + audio = ossia::make_audio_engine( + "", std::string(avnd::get_name()), "", "", want_ins, want_outs, + want_sample_rate, want_buffer_size); + + // Allocate buffers that may be required for converting float <-> double + avnd::process_setup setup_info{ + .input_channels = want_ins, + .output_channels = want_outs, + .frames_per_buffer = want_buffer_size, + .rate = (double)want_sample_rate}; + + processor.allocate_buffers(setup_info, float{}); + processor.allocate_buffers(setup_info, double{}); + + avnd::prepare(object, setup_info); + audio->set_tick([this](auto& st) { (*this)(st); }); + } + + void operator()(const ossia::audio_tick_state& st) + { + audio_tick tick = {.frames = (int)st.frames}; + int n = avnd::get_frames(tick); + auto ins = avnd::span{const_cast(st.inputs), (std::size_t)st.n_in}; + auto outs = avnd::span{st.outputs, (std::size_t)st.n_out}; + this->processor.process(object, ins, outs, tick); + } + + ~audio_mapper() + { + audio->stop(); + delete audio; + } +}; +} diff --git a/include/avnd/binding/standalone/oscquery_mapper.hpp b/include/avnd/binding/standalone/oscquery_mapper.hpp index 8e9d5bef..1acae3bc 100644 --- a/include/avnd/binding/standalone/oscquery_mapper.hpp +++ b/include/avnd/binding/standalone/oscquery_mapper.hpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -36,38 +35,15 @@ struct oscquery_mapper std::shared_ptr m_context; ossia::net::generic_device m_dev; - oscquery_mapper(avnd::effect_container& object) + explicit oscquery_mapper(avnd::effect_container& object, int osc_port, int ws_port) : object{object} , m_context{std::make_shared()} , m_dev{ std::make_unique( - m_context, 1234, 5678), + m_context, osc_port, ws_port), "my_device"} { create_ports(); - /* - // Create a few float parameters - 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); - } - - using namespace std::chrono_literals; - ossia::timer timer{m_context->context}; - timer.set_delay(100ms); - timer.start([&] { - for(auto param : my_params) - { - const auto v = param->value().get(); - param->push_value(3.7f * v * (1.f - v)); - } - }); - */ } template @@ -164,17 +140,17 @@ struct oscquery_mapper else if constexpr(std::is_same_v) return type == ossia::val_type::FLOAT || type == ossia::val_type::INT - || type == ossia::val_type::CHAR || type == ossia::val_type::BOOL; + || type == ossia::val_type::BOOL; else if constexpr(std::is_same_v) return type == ossia::val_type::FLOAT || type == ossia::val_type::INT - || type == ossia::val_type::CHAR || type == ossia::val_type::BOOL; + || type == ossia::val_type::BOOL; else if constexpr(std::floating_point) return type == ossia::val_type::FLOAT || type == ossia::val_type::INT - || type == ossia::val_type::CHAR || type == ossia::val_type::BOOL; + || type == ossia::val_type::BOOL; else if constexpr(std::integral) return type == ossia::val_type::FLOAT || type == ossia::val_type::INT - || type == ossia::val_type::CHAR || type == ossia::val_type::BOOL; + || type == ossia::val_type::BOOL; return false; } @@ -232,7 +208,7 @@ struct oscquery_mapper } else if constexpr(std::is_same_v) { - call_message_impl(ossia::convert(in)); + call_message_impl(ossia::convert(in).c_str()); } else if constexpr(std::is_same_v) { @@ -271,7 +247,7 @@ struct oscquery_mapper } else if constexpr(std::is_same_v) { - f(object.effect, ossia::convert(in)); + f(object.effect, ossia::convert(in).c_str()); } else if constexpr(std::is_same_v) { diff --git a/include/avnd/binding/standalone/prototype.cpp.in b/include/avnd/binding/standalone/prototype.cpp.in index c3177cf5..ca2b4c5d 100644 --- a/include/avnd/binding/standalone/prototype.cpp.in +++ b/include/avnd/binding/standalone/prototype.cpp.in @@ -1,11 +1,19 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ +#include +#include +#include +#include + #include <@AVND_MAIN_FILE@> -#include -#include -#include +#if AVND_STANDALONE_QML +#include +#include +#endif +// clang-format off using type = decltype(avnd::configure())::type; +// clang-format on void run_ui(auto& object) { @@ -28,32 +36,97 @@ void run_ui(auto& object) } #endif } + int main(int argc, char** argv) { - // Create the object - avnd::effect_container< type > object; - -#if 0 - // Create an oscquery interface to it. - standalone::oscquery_mapper< type > oscq{object}; - - std::thread t{[&] { oscq.run(); }}; -#endif + int in_channels = 2.; + int out_channels = 2.; + int buffer_size = 256.; + int sample_rate = 48000.; + int osc_port = 1234; + int ws_port = 5678; #if AVND_STANDALONE_QML qputenv("QML_DISABLE_DISTANCEFIELD", "1"); - qputenv("QT_SCALE_FACTOR", "2"); + qputenv("QT_SCALE_FACTOR", "1"); qputenv("QT_ASSUME_STDERR_HAS_CONSOLE", "1"); qputenv("QT_QUICK_CONTROLS_STYLE", "Material"); qputenv("QT_QUICK_CONTROLS_MATERIAL_THEME", "Dark"); + QCoreApplication::setApplicationName( + QString::fromStdString(std::string(avnd::get_name()))); + QCoreApplication::setApplicationVersion( + QString::fromStdString(std::string(avnd::get_version()))); + QCoreApplication::setOrganizationName( + QString::fromStdString(std::string(avnd::get_author()))); QGuiApplication app(argc, argv); + + { + QCommandLineParser parser; + parser.addHelpOption(); + parser.addVersionOption(); + auto opt_in_channels = (QCommandLineOption{ + {"i", "inputs"}, + QCoreApplication::translate("main", "Default input ."), + QCoreApplication::translate("main", "channels")}); + parser.addOption(opt_in_channels); + auto opt_out_channels = (QCommandLineOption{ + {"o", "outputs"}, + QCoreApplication::translate("main", "Default output ."), + QCoreApplication::translate("main", "channels")}); + parser.addOption(opt_out_channels); + auto opt_bs = (QCommandLineOption{ + {"b", "buffer-size"}, + QCoreApplication::translate("main", "Buffer in samples."), + QCoreApplication::translate("main", "size")}); + parser.addOption(opt_bs); + auto opt_rate = (QCommandLineOption{ + {"r", "rate"}, + QCoreApplication::translate("main", "Sample ."), + QCoreApplication::translate("main", "rate")}); + parser.addOption(opt_rate); + auto opt_osc = (QCommandLineOption{ + {"u", "udp"}, + QCoreApplication::translate("main", "OSCQuery over UDP."), + QCoreApplication::translate("main", "port")}); + parser.addOption(opt_osc); + auto opt_ws = (QCommandLineOption{ + {"w", "ws"}, + QCoreApplication::translate("main", "OSCQuery over WebSockets."), + QCoreApplication::translate("main", "port")}); + parser.addOption(opt_ws); + parser.process(app); + if(parser.isSet(opt_in_channels)) + in_channels = parser.value(opt_in_channels).toInt(); + if(parser.isSet(opt_out_channels)) + out_channels = parser.value(opt_out_channels).toInt(); + if(parser.isSet(opt_bs)) + buffer_size = parser.value(opt_bs).toInt(); + if(parser.isSet(opt_rate)) + sample_rate = parser.value(opt_rate).toInt(); + if(parser.isSet(opt_osc)) + osc_port = parser.value(opt_osc).toInt(); + if(parser.isSet(opt_ws)) + ws_port = parser.value(opt_ws).toInt(); + } #endif + // Create the object + avnd::effect_container object; + + avnd::init_controls(object); + + // Create an audio processor + standalone::audio_mapper audio{ + object, in_channels, out_channels, buffer_size, sample_rate}; + + // Create an oscquery interface to it. + standalone::oscquery_mapper oscq{object, osc_port, ws_port}; + + std::thread t{[&] { oscq.run(); }}; + run_ui(object); -#if 0 oscq.stop(); t.join(); -#endif } diff --git a/include/avnd/binding/standalone/standalone.hpp b/include/avnd/binding/standalone/standalone.hpp index 5db7c042..c90517d5 100644 --- a/include/avnd/binding/standalone/standalone.hpp +++ b/include/avnd/binding/standalone/standalone.hpp @@ -3,6 +3,7 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ #if __has_include() +#include #if __has_include() #define AVND_STANDALONE_OSCQUERY 1 #include diff --git a/include/avnd/concepts/processor.hpp b/include/avnd/concepts/processor.hpp index 9f1f5e17..90456449 100644 --- a/include/avnd/concepts/processor.hpp +++ b/include/avnd/concepts/processor.hpp @@ -132,7 +132,7 @@ concept mono_per_sample_arg_processor || std::is_invocable_r_v); template -concept mono_per_sample_port_invocations = +concept per_sample_port_invocations = (std::is_invocable_r_v || std::is_invocable_r_v || std::is_invocable_r_v @@ -146,13 +146,13 @@ template concept mono_per_sample_port_processor = (sample_input_port_count == 1) && (sample_output_port_count == 1) - && mono_per_sample_port_invocations; + && per_sample_port_invocations; template concept poly_per_sample_port_processor = ((sample_input_port_count > 1) || (sample_output_port_count > 1) || (sample_input_port_count != sample_output_port_count)) - && mono_per_sample_port_invocations; + && per_sample_port_invocations; /* template diff --git a/include/avnd/wrappers/process_execution.hpp b/include/avnd/wrappers/process_execution.hpp index 3d7f4f36..f5ecb2a7 100644 --- a/include/avnd/wrappers/process_execution.hpp +++ b/include/avnd/wrappers/process_execution.hpp @@ -107,6 +107,44 @@ auto current_tick(avnd::effect_container& implementation, const Tick& tick_da } } +template + requires requires(Tick t) { t.frames = 1; } +auto current_tick(avnd::effect_container& implementation, const Tick& tick_data) +{ + // Nice little C++20 goodie: remove_cvref_t + // unused in the end using tick_setup_t = std::remove_cvref_t>; + if constexpr(has_tick) + { + using tick_t = typename T::tick; + static_assert(std::is_aggregate_v); + + tick_t t{}; + if_possible(t.frames = tick_data.frames); + if_possible(t.relative_position = tick_data.relative_position); + if_possible(t.parent_duration = tick_data.parent_duration); + if_possible(t.speed = tick_data.speed); + if_possible(t.tempo = tick_data.tempo); + if constexpr( + requires { t.signature; } && requires { tick_data.signature; }) + { + auto [num, denom] = tick_data.signature; + t.signature = {num, denom}; + } + if_possible(t.position_in_frames = tick_data.position_in_frames); + if_possible(t.position_in_seconds = tick_data.position_in_seconds); + if_possible(t.position_in_nanoseconds = tick_data.position_in_nanoseconds); + if_possible(t.start_position_in_quarters = tick_data.start_position_in_quarters); + if_possible(t.end_position_in_quarters = tick_data.end_position_in_quarters); + + // Position of the last bar relative to start in quarter notes + if_possible(t.bar_at_start = tick_data.bar_at_start); + + // Position of the last bar relative to end in quarter notes + if_possible(t.bar_at_end = tick_data.bar_at_end); + + return t; + } +} inline constexpr auto get_frames(std::integral auto v) { return v; @@ -119,6 +157,13 @@ inline constexpr auto get_frames(const Tick& v) return v.frames(); } +template + requires requires(Tick t) { t.frames = 1; } +inline constexpr auto get_frames(const Tick& v) +{ + return v.frames; +} + template inline constexpr auto get_tick_or_frames(avnd::effect_container& implementation, std::integral auto v) @@ -136,6 +181,18 @@ get_tick_or_frames(avnd::effect_container& implementation, std::integral auto return v; } } + +template + requires requires(Tick t) { t.frames = 1; } +inline constexpr auto +get_tick_or_frames(avnd::effect_container& implementation, const Tick& v) +{ + if constexpr(avnd::has_tick) + return current_tick(implementation, v); + else + return v.frames; +} + template requires requires(Tick t) { t.frames(); } inline constexpr auto diff --git a/include/avnd/wrappers/smooth.hpp b/include/avnd/wrappers/smooth.hpp index d5657757..3057a101 100644 --- a/include/avnd/wrappers/smooth.hpp +++ b/include/avnd/wrappers/smooth.hpp @@ -6,9 +6,8 @@ #include #include #include +#include #include -#include -#include #include namespace avnd