From e1d0c9e26f8ecbe327b18d6bb5eb7d301122419a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Mon, 24 Jun 2024 07:48:21 -0400 Subject: [PATCH] [core] Fix some tests and refactor files --- src/ossia/dataflow/audio_lock.hpp | 34 ++ .../dataflow/execution/default_policy.cpp | 1 + .../dataflow/execution/default_policy.hpp | 3 +- .../dataflow/execution/direct_policy.cpp | 6 +- .../dataflow/execution/direct_policy.hpp | 1 + .../dataflow/execution/execution_policy.cpp | 351 +----------------- .../dataflow/execution/execution_policy.hpp | 130 ++----- .../local_state_execution_policy.cpp | 350 +++++++++++++++++ .../local_state_execution_policy.hpp | 51 +++ .../dataflow/execution/merged_policy.cpp | 1 + .../dataflow/execution/merged_policy.hpp | 11 +- .../dataflow/execution/ordered_policy.cpp | 1 + .../dataflow/execution/ordered_policy.hpp | 4 +- .../dataflow/execution/priorized_policy.cpp | 3 + .../dataflow/execution/priorized_policy.hpp | 3 +- .../dataflow/execution/pull_visitors.hpp | 5 +- .../dataflow/execution/to_state_element.hpp | 28 ++ src/ossia/detail/config.hpp | 6 + src/ossia/network/value/format_value.hpp | 11 +- src/ossia_sources.cmake | 40 +- 20 files changed, 546 insertions(+), 494 deletions(-) create mode 100644 src/ossia/dataflow/audio_lock.hpp create mode 100644 src/ossia/dataflow/execution/local_state_execution_policy.cpp create mode 100644 src/ossia/dataflow/execution/local_state_execution_policy.hpp create mode 100644 src/ossia/dataflow/execution/to_state_element.hpp diff --git a/src/ossia/dataflow/audio_lock.hpp b/src/ossia/dataflow/audio_lock.hpp new file mode 100644 index 00000000000..292fafef04e --- /dev/null +++ b/src/ossia/dataflow/audio_lock.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include +#include + +#include + +#if defined(OSSIA_PARALLEL) +using ossia_audio_lock_t = std::unique_lock; +#define OSSIA_EXEC_STATE_LOCK_READ(state) \ + ossia_audio_lock_t ossia_read_lock \ + { \ + (state).mutex \ + } +#define OSSIA_EXEC_STATE_LOCK_WRITE(state) \ + ossia_audio_lock_t ossia_write_lock \ + { \ + (state).mutex \ + } +#else +struct ossia_audio_lock_t +{ + void lock() { } + void unlock() { } +}; +#define OSSIA_EXEC_STATE_LOCK_READ(state) \ + ossia_audio_lock_t ossia_read_lock; \ + (void)ossia_read_lock; +#define OSSIA_EXEC_STATE_LOCK_WRITE(state) \ + ossia_audio_lock_t ossia_write_lock; \ + (void)ossia_write_lock; +#endif diff --git a/src/ossia/dataflow/execution/default_policy.cpp b/src/ossia/dataflow/execution/default_policy.cpp index c86782a9152..eaa06011980 100644 --- a/src/ossia/dataflow/execution/default_policy.cpp +++ b/src/ossia/dataflow/execution/default_policy.cpp @@ -1,5 +1,6 @@ #include "default_policy.hpp" +#include #include namespace ossia diff --git a/src/ossia/dataflow/execution/default_policy.hpp b/src/ossia/dataflow/execution/default_policy.hpp index 07496a840f5..d45a665414b 100644 --- a/src/ossia/dataflow/execution/default_policy.hpp +++ b/src/ossia/dataflow/execution/default_policy.hpp @@ -1,5 +1,6 @@ #pragma once -#include +#include +#include namespace ossia { diff --git a/src/ossia/dataflow/execution/direct_policy.cpp b/src/ossia/dataflow/execution/direct_policy.cpp index c22ff255392..b1f057cdc12 100644 --- a/src/ossia/dataflow/execution/direct_policy.cpp +++ b/src/ossia/dataflow/execution/direct_policy.cpp @@ -1,13 +1,13 @@ -#undef NDEBUG #include "direct_policy.hpp" +#include +#include +#include #include #include #include #include -#include - namespace ossia { static thread_local std::vector g_direct_policy_message_cache diff --git a/src/ossia/dataflow/execution/direct_policy.hpp b/src/ossia/dataflow/execution/direct_policy.hpp index 70c94226c00..622d50f5f35 100644 --- a/src/ossia/dataflow/execution/direct_policy.hpp +++ b/src/ossia/dataflow/execution/direct_policy.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include diff --git a/src/ossia/dataflow/execution/execution_policy.cpp b/src/ossia/dataflow/execution/execution_policy.cpp index a914f0dc100..8678759cb38 100644 --- a/src/ossia/dataflow/execution/execution_policy.cpp +++ b/src/ossia/dataflow/execution/execution_policy.cpp @@ -1,353 +1,6 @@ #include "execution_policy.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - namespace ossia { - -execution_state_policy::execution_state_policy() { } -execution_state_policy::~execution_state_policy() { } - -local_state_execution_policy::local_state_execution_policy() -{ - m_valueState.reserve(100); -#if defined(OSSIA_PROTOCOL_AUDIO) - m_audioState.reserve(8); -#endif - -#if defined(OSSIA_PROTOCOL_MIDI) - m_midiState.reserve(4); -#endif -} - -local_state_execution_policy::~local_state_execution_policy() { } - -void local_state_execution_policy::commit_common() -{ -#if defined(OSSIA_PROTOCOL_AUDIO) - // FIXME this does not look necessary? - // Why not just push to the audio address - for(auto& elt : m_audioState) - { - assert(elt.first); - elt.first->push_value(elt.second); - - for(auto& vec : elt.second.get()) - { - vec.clear(); - } - } -#endif - -#if defined(OSSIA_PROTOCOL_MIDI) - for(auto& elt : m_midiState) - { - if(!elt.second.empty()) - { - auto proto = dynamic_cast( - &elt.first->get_node().get_device().get_protocol()); - if(proto) - { - for(const auto& v : elt.second) - { - proto->push_value(v); - } - } - elt.second.clear(); - } - } -#endif -} - -// Note: this should be combined with the code in the commit_ methods -// in order to handle both domain and unit conversion in a single place... - -static void map_value_to_param( - const ossia::net::parameter_base& param, const ossia::timed_value& v, - const ossia::value_port& val, int idx, - value_vector>& out, ossia_audio_lock_t& lck) -{ - auto& tgt_domain = param.get_domain(); - if(!val.index.empty()) - { - if(val.type.target()) - { - lck.lock(); - out.emplace_back( - std::piecewise_construct, std::forward_as_tuple(v, val.index), - std::forward_as_tuple(idx)); - lck.unlock(); - } - else - { - lck.lock(); - out.emplace_back( - std::piecewise_construct, std::forward_as_tuple(v, val.index, val.type), - std::forward_as_tuple(idx)); - lck.unlock(); - } - - return; - } - - if(val.type.target() || !tgt_domain || !val.domain) - { - lck.lock(); - out.emplace_back( - std::piecewise_construct, std::forward_as_tuple(v), std::forward_as_tuple(idx)); - lck.unlock(); - return; - } - - { - - lck.lock(); - auto& ret = out.emplace_back( - std::piecewise_construct, std::forward_as_tuple(v, val.type), - std::forward_as_tuple(idx)) - .first; - - // FIXME won't work in the merge case for same timestamps, both can write at the same time - lck.unlock(); - - // Map to the target domain - map_value(ret.value, ossia::destination_index{}, val.domain, tgt_domain); - - // Convert to the parameter type - ossia::convert_inplace(ret.value, param.get_value_type()); - } -} - -static ossia::typed_value map_value_to_param( - const ossia::net::parameter_base& param, const ossia::timed_value& v, - const ossia::value_port& val) -{ - ossia::typed_value ret{v, val.index, val.type}; - auto& tgt_domain = param.get_domain(); - if(!val.index.empty()) - goto def_case; - - if(!tgt_domain) - goto def_case; - - if(!val.domain) - goto def_case; - - if(val.type.target()) - goto def_case; - - { - // Map to the target domain - map_value(ret.value, ossia::destination_index{}, val.domain, tgt_domain); - - // Convert to the parameter type - ossia::convert_inplace(ret.value, param.get_value_type()); - } - -def_case: - return ret; -} - -static ossia::typed_value map_value_to_param( - const ossia::net::parameter_base& param, ossia::timed_value&& v, - const ossia::value_port& val) -{ - auto& tgt_domain = param.get_domain(); - if(!val.index.empty()) - goto def_case; - - if(!tgt_domain) - goto def_case; - - if(!val.domain) - goto def_case; - - if(val.type.target()) - goto def_case; - - { - // Map to the target domain - map_value(v.value, ossia::destination_index{}, val.domain, tgt_domain); - - // Convert to the parameter type - auto vv = ossia::convert(std::move(v.value), param.get_value_type()); - - return ossia::typed_value{std::move(vv), val.index, val.type}; - } - -def_case: - return ossia::typed_value{std::move(v), val.index, val.type}; -} - -void local_state_execution_policy::insert( - ossia::net::parameter_base& param, const value_port& val) -{ - OSSIA_EXEC_STATE_LOCK_WRITE(*this); - int idx = m_msgIndex; - auto& st = m_valueState[¶m]; - st.reserve(st.size() + val.get_data().size()); - ossia_write_lock.unlock(); - - // here reserve is a pessimization if we push only a few values... - // just letting log2 growth do its job is much better. - switch(val.mix_method) - { - case ossia::data_mix_method::mix_replace: { - for(const ossia::timed_value& v : val.get_data()) - { - auto it = ossia::find_if(st, [&](const std::pair& val) { - return val.first.timestamp == v.timestamp; - }); - if(it != st.end()) - { - it->first = map_value_to_param(param, v, val); - } - else - { - map_value_to_param(param, v, val, idx++, st, ossia_write_lock); - } - } - break; - } - case ossia::data_mix_method::mix_append: { - for(const auto& v : val.get_data()) - { - map_value_to_param(param, v, val, idx++, st, ossia_write_lock); - } - break; - } - case ossia::data_mix_method::mix_merge: { - // TODO; - break; - } - } - idx = m_msgIndex; - m_msgIndex += val.get_data().size(); -} - -void local_state_execution_policy::insert( - ossia::audio_parameter& param, const audio_port& v) -{ -#if defined(OSSIA_PROTOCOL_AUDIO) - OSSIA_EXEC_STATE_LOCK_WRITE(*this); - mix(v.get(), m_audioState[¶m].get()); -#endif -} - -void local_state_execution_policy::insert( - ossia::net::midi::midi_parameter& param, const midi_port& v) -{ -#if defined(OSSIA_PROTOCOL_MIDI) - if(!v.messages.empty()) - { - OSSIA_EXEC_STATE_LOCK_WRITE(*this); - auto& vec = m_midiState[¶m]; - vec.insert(vec.end(), v.messages.begin(), v.messages.end()); - } -#endif -} - -struct state_exec_visitor -{ - ossia::local_state_execution_policy& e; - void operator()(const ossia::state& st) - { - for(auto& msg : st) - ossia::apply(*this, msg); - } - - void operator()(const ossia::message& msg) - { - OSSIA_EXEC_STATE_LOCK_WRITE(e); - e.m_valueState[&msg.dest.address()].emplace_back( - ossia::typed_value{msg.message_value, msg.dest.index, msg.dest.unit}, - e.m_msgIndex++); - } - - template - void operator()(const ossia::piecewise_vec_message& st) - { - } - - void operator()(const ossia::piecewise_message& st) { } - - void operator()(const ossia::monostate&) { } -}; - -static bool is_in( - net::parameter_base& other, - const ossia::hash_map< - ossia::net::parameter_base*, value_vector>>& - container) -{ - auto it = container.find(&other); - if(it == container.end()) - return false; - return !it->second.empty(); -} -static bool is_in( - net::parameter_base& other, - const ossia::hash_map>& - container) -{ -#if defined(OSSIA_PROTOCOL_AUDIO) - auto it = container.find(&other); - if(it == container.end()) - return false; - return !it->second.empty(); -#else - return false; -#endif -} -static bool is_in( - net::parameter_base& other, - const ossia::hash_map& container) -{ -#if defined(OSSIA_PROTOCOL_AUDIO) - // TODO dangerous - auto it = container.find(static_cast(&other)); - if(it == container.end()) - return false; - return !it->second.empty(); -#else - return false; -#endif -} -bool local_state_execution_policy::in_local_scope(net::parameter_base& other) const -{ - OSSIA_EXEC_STATE_LOCK_READ(*this); - return ( - is_in(other, m_valueState) || is_in(other, m_audioState) - || is_in(other, m_midiState)); -} - -void local_state_execution_policy::clear_local_state() -{ - m_msgIndex = 0; - /* - for(auto& st : m_valueState) - st.second.clear(); - for(auto& st : m_audioState) - for(auto& samples : st.second.samples) - samples.clear(); - for(auto& st : m_midiState) - st.second.clear(); - */ -} - -bool local_state_execution_policy::find_and_copy(net::parameter_base& addr, inlet& in) -{ - return in.visit(local_pull_visitor{*this, &addr}); -} +execution_state_policy::execution_state_policy() = default; +execution_state_policy::~execution_state_policy() = default; } diff --git a/src/ossia/dataflow/execution/execution_policy.hpp b/src/ossia/dataflow/execution/execution_policy.hpp index f985ca18012..43bc5cb5a2d 100644 --- a/src/ossia/dataflow/execution/execution_policy.hpp +++ b/src/ossia/dataflow/execution/execution_policy.hpp @@ -1,65 +1,35 @@ #pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(OSSIA_SMALL_VECTOR) -#include -#endif - -#include +#include #if SIZE_MAX == 0xFFFFFFFF // 32-bit #include #include #include #endif -#include - -#include - -#if defined(OSSIA_PARALLEL) -using ossia_audio_lock_t = std::unique_lock; -#define OSSIA_EXEC_STATE_LOCK_READ(state) \ - ossia_audio_lock_t ossia_read_lock \ - { \ - (state).mutex \ - } -#define OSSIA_EXEC_STATE_LOCK_WRITE(state) \ - ossia_audio_lock_t ossia_write_lock \ - { \ - (state).mutex \ - } -#else -struct ossia_audio_lock_t -{ - void lock() { } - void unlock() { } -}; -#define OSSIA_EXEC_STATE_LOCK_READ(state) \ - ossia_audio_lock_t ossia_read_lock; \ - (void)ossia_read_lock; -#define OSSIA_EXEC_STATE_LOCK_WRITE(state) \ - ossia_audio_lock_t ossia_write_lock; \ - (void)ossia_write_lock; -#endif namespace ossia { - -struct execution_state_policy +namespace net +{ +class parameter_base; +namespace midi +{ +class midi_parameter; +} +} +class audio_parameter; +struct audio_port; +struct value_port; +struct midi_port; +struct inlet; +struct outlet; +struct OSSIA_TEST_EXPORT execution_state_policy { execution_state_policy(); + execution_state_policy(const execution_state_policy&) = delete; + execution_state_policy(execution_state_policy&&) = delete; + execution_state_policy& operator=(const execution_state_policy&) = delete; + execution_state_policy& operator=(execution_state_policy&&) = delete; + virtual ~execution_state_policy(); virtual void commit() = 0; @@ -74,62 +44,4 @@ struct execution_state_policy virtual void insert(ossia::audio_parameter& dest, const audio_port& v) = 0; virtual void insert(ossia::net::midi::midi_parameter& dest, const midi_port& v) = 0; }; - -struct local_state_execution_policy : execution_state_policy -{ - local_state_execution_policy(); - virtual ~local_state_execution_policy(); - - bool find_and_copy(net::parameter_base& addr, inlet& in) override; - void clear_local_state() override; - - void commit_common(); - - bool in_local_scope(net::parameter_base& other) const override; - - void insert(ossia::net::parameter_base& dest, const ossia::value_port& v) override; - void insert(ossia::audio_parameter& dest, const audio_port& v) override; - void insert(ossia::net::midi::midi_parameter& dest, const midi_port& v) override; - - mutable ossia::audio_spin_mutex mutex; - // private:// disabled due to tests, but for some reason can't make friend - // work - // using value_state_impl = ossia::flat_multimap>; - - TS_GUARDED_BY(mutex) - ossia::hash_map>> - m_valueState; - - TS_GUARDED_BY(mutex) - ossia::hash_map m_audioState; - - TS_GUARDED_BY(mutex) - ossia::hash_map> - m_midiState; - - TS_GUARDED_BY(mutex) - int m_msgIndex{}; -}; - -inline ossia::message -to_state_element(ossia::net::parameter_base& p, ossia::typed_value&& v) -{ - ossia::message m{p, std::move(v.value)}; - if(auto u = v.type.target()) - m.dest.unit = std::move(*u); - m.dest.index = std::move(v.index); - return m; -} - -inline ossia::message -to_state_element(ossia::net::parameter_base& p, const ossia::typed_value& v) -{ - ossia::message m{p, v.value}; - if(auto u = v.type.target()) - m.dest.unit = std::move(*u); - m.dest.index = std::move(v.index); - return m; -} - } diff --git a/src/ossia/dataflow/execution/local_state_execution_policy.cpp b/src/ossia/dataflow/execution/local_state_execution_policy.cpp new file mode 100644 index 00000000000..03c756f8e18 --- /dev/null +++ b/src/ossia/dataflow/execution/local_state_execution_policy.cpp @@ -0,0 +1,350 @@ +#include "local_state_execution_policy.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ossia +{ +local_state_execution_policy::local_state_execution_policy() +{ + m_valueState.reserve(100); +#if defined(OSSIA_PROTOCOL_AUDIO) + m_audioState.reserve(8); +#endif + +#if defined(OSSIA_PROTOCOL_MIDI) + m_midiState.reserve(4); +#endif +} + +local_state_execution_policy::~local_state_execution_policy() { } + +void local_state_execution_policy::commit_common() +{ +#if defined(OSSIA_PROTOCOL_AUDIO) + // FIXME this does not look necessary? + // Why not just push to the audio address + for(auto& elt : m_audioState) + { + assert(elt.first); + elt.first->push_value(elt.second); + + for(auto& vec : elt.second.get()) + { + vec.clear(); + } + } +#endif + +#if defined(OSSIA_PROTOCOL_MIDI) + for(auto& elt : m_midiState) + { + if(!elt.second.empty()) + { + auto proto = dynamic_cast( + &elt.first->get_node().get_device().get_protocol()); + if(proto) + { + for(const auto& v : elt.second) + { + proto->push_value(v); + } + } + elt.second.clear(); + } + } +#endif +} + +// Note: this should be combined with the code in the commit_ methods +// in order to handle both domain and unit conversion in a single place... + +static void map_value_to_param( + const ossia::net::parameter_base& param, const ossia::timed_value& v, + const ossia::value_port& val, int idx, + value_vector>& out, ossia_audio_lock_t& lck) +{ + auto& tgt_domain = param.get_domain(); + if(!val.index.empty()) + { + if(val.type.target()) + { + lck.lock(); + out.emplace_back( + std::piecewise_construct, std::forward_as_tuple(v, val.index), + std::forward_as_tuple(idx)); + lck.unlock(); + } + else + { + lck.lock(); + out.emplace_back( + std::piecewise_construct, std::forward_as_tuple(v, val.index, val.type), + std::forward_as_tuple(idx)); + lck.unlock(); + } + + return; + } + + if(val.type.target() || !tgt_domain || !val.domain) + { + lck.lock(); + out.emplace_back( + std::piecewise_construct, std::forward_as_tuple(v), std::forward_as_tuple(idx)); + lck.unlock(); + return; + } + + { + + lck.lock(); + auto& ret = out.emplace_back( + std::piecewise_construct, std::forward_as_tuple(v, val.type), + std::forward_as_tuple(idx)) + .first; + + // FIXME won't work in the merge case for same timestamps, both can write at the same time + lck.unlock(); + + // Map to the target domain + map_value(ret.value, ossia::destination_index{}, val.domain, tgt_domain); + + // Convert to the parameter type + ossia::convert_inplace(ret.value, param.get_value_type()); + } +} + +static ossia::typed_value map_value_to_param( + const ossia::net::parameter_base& param, const ossia::timed_value& v, + const ossia::value_port& val) +{ + ossia::typed_value ret{v, val.index, val.type}; + auto& tgt_domain = param.get_domain(); + if(!val.index.empty()) + goto def_case; + + if(!tgt_domain) + goto def_case; + + if(!val.domain) + goto def_case; + + if(val.type.target()) + goto def_case; + + { + // Map to the target domain + map_value(ret.value, ossia::destination_index{}, val.domain, tgt_domain); + + // Convert to the parameter type + ossia::convert_inplace(ret.value, param.get_value_type()); + } + +def_case: + return ret; +} + +static ossia::typed_value map_value_to_param( + const ossia::net::parameter_base& param, ossia::timed_value&& v, + const ossia::value_port& val) +{ + auto& tgt_domain = param.get_domain(); + if(!val.index.empty()) + goto def_case; + + if(!tgt_domain) + goto def_case; + + if(!val.domain) + goto def_case; + + if(val.type.target()) + goto def_case; + + { + // Map to the target domain + map_value(v.value, ossia::destination_index{}, val.domain, tgt_domain); + + // Convert to the parameter type + auto vv = ossia::convert(std::move(v.value), param.get_value_type()); + + return ossia::typed_value{std::move(vv), val.index, val.type}; + } + +def_case: + return ossia::typed_value{std::move(v), val.index, val.type}; +} + +void local_state_execution_policy::insert( + ossia::net::parameter_base& param, const value_port& val) +{ + OSSIA_EXEC_STATE_LOCK_WRITE(*this); + int idx = m_msgIndex; + auto& st = m_valueState[¶m]; + st.reserve(st.size() + val.get_data().size()); + ossia_write_lock.unlock(); + + // here reserve is a pessimization if we push only a few values... + // just letting log2 growth do its job is much better. + switch(val.mix_method) + { + case ossia::data_mix_method::mix_replace: { + for(const ossia::timed_value& v : val.get_data()) + { + auto it = ossia::find_if(st, [&](const std::pair& val) { + return val.first.timestamp == v.timestamp; + }); + if(it != st.end()) + { + it->first = map_value_to_param(param, v, val); + } + else + { + map_value_to_param(param, v, val, idx++, st, ossia_write_lock); + } + } + break; + } + case ossia::data_mix_method::mix_append: { + for(const auto& v : val.get_data()) + { + map_value_to_param(param, v, val, idx++, st, ossia_write_lock); + } + break; + } + case ossia::data_mix_method::mix_merge: { + // TODO; + break; + } + } + idx = m_msgIndex; + m_msgIndex += val.get_data().size(); +} + +void local_state_execution_policy::insert( + ossia::audio_parameter& param, const audio_port& v) +{ +#if defined(OSSIA_PROTOCOL_AUDIO) + OSSIA_EXEC_STATE_LOCK_WRITE(*this); + mix(v.get(), m_audioState[¶m].get()); +#endif +} + +void local_state_execution_policy::insert( + ossia::net::midi::midi_parameter& param, const midi_port& v) +{ +#if defined(OSSIA_PROTOCOL_MIDI) + if(!v.messages.empty()) + { + OSSIA_EXEC_STATE_LOCK_WRITE(*this); + auto& vec = m_midiState[¶m]; + vec.insert(vec.end(), v.messages.begin(), v.messages.end()); + } +#endif +} + +struct state_exec_visitor +{ + ossia::local_state_execution_policy& e; + void operator()(const ossia::state& st) + { + for(auto& msg : st) + ossia::apply(*this, msg); + } + + void operator()(const ossia::message& msg) + { + OSSIA_EXEC_STATE_LOCK_WRITE(e); + e.m_valueState[&msg.dest.address()].emplace_back( + ossia::typed_value{msg.message_value, msg.dest.index, msg.dest.unit}, + e.m_msgIndex++); + } + + template + void operator()(const ossia::piecewise_vec_message& st) + { + } + + void operator()(const ossia::piecewise_message& st) { } + + void operator()(const ossia::monostate&) { } +}; + +static bool is_in( + net::parameter_base& other, + const ossia::hash_map< + ossia::net::parameter_base*, value_vector>>& + container) +{ + auto it = container.find(&other); + if(it == container.end()) + return false; + return !it->second.empty(); +} +static bool is_in( + net::parameter_base& other, + const ossia::hash_map>& + container) +{ +#if defined(OSSIA_PROTOCOL_AUDIO) + auto it = container.find(&other); + if(it == container.end()) + return false; + return !it->second.empty(); +#else + return false; +#endif +} +static bool is_in( + net::parameter_base& other, + const ossia::hash_map& container) +{ +#if defined(OSSIA_PROTOCOL_AUDIO) + // TODO dangerous + auto it = container.find(static_cast(&other)); + if(it == container.end()) + return false; + return !it->second.empty(); +#else + return false; +#endif +} + +bool local_state_execution_policy::in_local_scope(net::parameter_base& other) const +{ + OSSIA_EXEC_STATE_LOCK_READ(*this); + return ( + is_in(other, m_valueState) || is_in(other, m_audioState) + || is_in(other, m_midiState)); +} + +void local_state_execution_policy::clear_local_state() +{ + m_msgIndex = 0; + /* + for(auto& st : m_valueState) + st.second.clear(); + for(auto& st : m_audioState) + for(auto& samples : st.second.samples) + samples.clear(); + for(auto& st : m_midiState) + st.second.clear(); + */ +} + +bool local_state_execution_policy::find_and_copy(net::parameter_base& addr, inlet& in) +{ + return in.visit(local_pull_visitor{*this, &addr}); +} +} diff --git a/src/ossia/dataflow/execution/local_state_execution_policy.hpp b/src/ossia/dataflow/execution/local_state_execution_policy.hpp new file mode 100644 index 00000000000..6d880d131bb --- /dev/null +++ b/src/ossia/dataflow/execution/local_state_execution_policy.hpp @@ -0,0 +1,51 @@ +#pragma once +#include +#include +#include +#include +#include + +#if defined(OSSIA_SMALL_VECTOR) +#include +#endif + +namespace ossia +{ + +struct OSSIA_TEST_EXPORT local_state_execution_policy : execution_state_policy +{ + local_state_execution_policy(); + virtual ~local_state_execution_policy(); + + bool find_and_copy(net::parameter_base& addr, inlet& in) override; + void clear_local_state() override; + + void commit_common(); + + bool in_local_scope(net::parameter_base& other) const override; + + void insert(ossia::net::parameter_base& dest, const ossia::value_port& v) override; + void insert(ossia::audio_parameter& dest, const audio_port& v) override; + void insert(ossia::net::midi::midi_parameter& dest, const midi_port& v) override; + + mutable ossia::audio_spin_mutex mutex; + // private:// disabled due to tests, but for some reason can't make friend + // work + // using value_state_impl = ossia::flat_multimap>; + + TS_GUARDED_BY(mutex) + ossia::hash_map>> + m_valueState; + + TS_GUARDED_BY(mutex) + ossia::hash_map m_audioState; + + TS_GUARDED_BY(mutex) + ossia::hash_map> + m_midiState; + + TS_GUARDED_BY(mutex) + int m_msgIndex{}; +}; +} diff --git a/src/ossia/dataflow/execution/merged_policy.cpp b/src/ossia/dataflow/execution/merged_policy.cpp index d638cb2b28f..6beb89e5525 100644 --- a/src/ossia/dataflow/execution/merged_policy.cpp +++ b/src/ossia/dataflow/execution/merged_policy.cpp @@ -1,5 +1,6 @@ #include "merged_policy.hpp" +#include #include namespace ossia diff --git a/src/ossia/dataflow/execution/merged_policy.hpp b/src/ossia/dataflow/execution/merged_policy.hpp index 634ec433f9f..e417aa50f44 100644 --- a/src/ossia/dataflow/execution/merged_policy.hpp +++ b/src/ossia/dataflow/execution/merged_policy.hpp @@ -1,17 +1,12 @@ #pragma once -#include +#include +#include #include -#include - namespace ossia { -struct -#if defined(OSSIA_TESTING) - OSSIA_EXPORT -#endif - merged_execution_state_policy : local_state_execution_policy +struct OSSIA_TEST_EXPORT merged_execution_state_policy : local_state_execution_policy { void commit() override; ossia::mono_state m_monoState; diff --git a/src/ossia/dataflow/execution/ordered_policy.cpp b/src/ossia/dataflow/execution/ordered_policy.cpp index d7f6c44cab5..474440e37dc 100644 --- a/src/ossia/dataflow/execution/ordered_policy.cpp +++ b/src/ossia/dataflow/execution/ordered_policy.cpp @@ -1,5 +1,6 @@ #include "ordered_policy.hpp" +#include #include namespace ossia diff --git a/src/ossia/dataflow/execution/ordered_policy.hpp b/src/ossia/dataflow/execution/ordered_policy.hpp index 621ee5feb7e..cc60adb153c 100644 --- a/src/ossia/dataflow/execution/ordered_policy.hpp +++ b/src/ossia/dataflow/execution/ordered_policy.hpp @@ -1,5 +1,7 @@ #pragma once -#include +#include +#include +#include namespace ossia { diff --git a/src/ossia/dataflow/execution/priorized_policy.cpp b/src/ossia/dataflow/execution/priorized_policy.cpp index b3e4a357670..37e61e16e79 100644 --- a/src/ossia/dataflow/execution/priorized_policy.cpp +++ b/src/ossia/dataflow/execution/priorized_policy.cpp @@ -1,6 +1,9 @@ #include "priorized_policy.hpp" +#include +#include #include +#include namespace ossia { diff --git a/src/ossia/dataflow/execution/priorized_policy.hpp b/src/ossia/dataflow/execution/priorized_policy.hpp index 2dab5fbfc65..eded877572f 100644 --- a/src/ossia/dataflow/execution/priorized_policy.hpp +++ b/src/ossia/dataflow/execution/priorized_policy.hpp @@ -1,5 +1,6 @@ #pragma once -#include +#include +#include namespace ossia { diff --git a/src/ossia/dataflow/execution/pull_visitors.hpp b/src/ossia/dataflow/execution/pull_visitors.hpp index 22463277038..8756870a100 100644 --- a/src/ossia/dataflow/execution/pull_visitors.hpp +++ b/src/ossia/dataflow/execution/pull_visitors.hpp @@ -1,10 +1,11 @@ #pragma once +#include +#include #include -#include +#include #include #include #include - namespace ossia { diff --git a/src/ossia/dataflow/execution/to_state_element.hpp b/src/ossia/dataflow/execution/to_state_element.hpp new file mode 100644 index 00000000000..7bc3577100a --- /dev/null +++ b/src/ossia/dataflow/execution/to_state_element.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include + +namespace ossia +{ + +inline ossia::message +to_state_element(ossia::net::parameter_base& p, ossia::typed_value&& v) +{ + ossia::message m{p, std::move(v.value)}; + if(auto u = v.type.target()) + m.dest.unit = std::move(*u); + m.dest.index = std::move(v.index); + return m; +} + +inline ossia::message +to_state_element(ossia::net::parameter_base& p, const ossia::typed_value& v) +{ + ossia::message m{p, v.value}; + if(auto u = v.type.target()) + m.dest.unit = std::move(*u); + m.dest.index = std::move(v.index); + return m; +} + +} diff --git a/src/ossia/detail/config.hpp b/src/ossia/detail/config.hpp index 40c48e79e14..c7d017bfad4 100644 --- a/src/ossia/detail/config.hpp +++ b/src/ossia/detail/config.hpp @@ -127,3 +127,9 @@ #if !defined(QT_NO_KEYWORDS) #define QT_NO_KEYWORDS 1 #endif + +#if defined(OSSIA_TESTING) +#define OSSIA_TEST_EXPORT OSSIA_EXPORT +#else +#define OSSIA_TEST_EXPORT +#endif diff --git a/src/ossia/network/value/format_value.hpp b/src/ossia/network/value/format_value.hpp index 5324734b801..61bcfbcb31a 100644 --- a/src/ossia/network/value/format_value.hpp +++ b/src/ossia/network/value/format_value.hpp @@ -97,7 +97,7 @@ inline fmt_ctx::iterator value_prettyprint_visitor::operator()(int32_t i) const inline fmt_ctx::iterator value_prettyprint_visitor::operator()(float f) const { - return fmt::format_to(ctx.out(), "float: {}", f); + return fmt::format_to(ctx.out(), "float: {:.2f}", f); } inline fmt_ctx::iterator value_prettyprint_visitor::operator()(bool b) const @@ -118,17 +118,20 @@ inline fmt_ctx::iterator value_prettyprint_visitor::operator()(std::string str) inline fmt_ctx::iterator value_prettyprint_visitor::operator()(vec2f vec) const { - return fmt::format_to(ctx.out(), "vec2f: {}", vec); + return fmt::format_to(ctx.out(), "vec2f: [{:.2f}, {:.2f}]", vec[0], vec[1]); } inline fmt_ctx::iterator value_prettyprint_visitor::operator()(vec3f vec) const { - return fmt::format_to(ctx.out(), "vec3f: {}", vec); + return fmt::format_to( + ctx.out(), "vec3f: [{:.2f}, {:.2f}, {:.2f}]", vec[0], vec[1], vec[2]); } inline fmt_ctx::iterator value_prettyprint_visitor::operator()(vec4f vec) const { - return fmt::format_to(ctx.out(), "vec4f: {}", vec); + return fmt::format_to( + ctx.out(), "vec4f: [{:.2f}, {:.2f}, {:.2f}, {:.2f}]", vec[0], vec[1], vec[2], + vec[3]); } inline fmt_ctx::iterator diff --git a/src/ossia_sources.cmake b/src/ossia_sources.cmake index 2b6b74d242b..fa7add4cdb7 100644 --- a/src/ossia_sources.cmake +++ b/src/ossia_sources.cmake @@ -11,13 +11,12 @@ set(API_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/buffer_pool.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/callback_container.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/case_insensitive.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/closest_element.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/concepts.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/config.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/closest_element.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/constexpr_string_map.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/dylib_loader.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/instantiations.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/destination_index.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/dylib_loader.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/enum_map.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/flat_map.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/flat_set.hpp" @@ -31,6 +30,7 @@ set(API_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/hash_map.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/json.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/json_fwd.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/instantiations.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/libav.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/locked_container.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/lockfree_queue.hpp" @@ -64,6 +64,7 @@ set(API_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/timer.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/to_string.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/to_tuple.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/triple_buffer.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/typelist.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/detail/variant.hpp" @@ -667,48 +668,54 @@ set(OSSIA_DATAFLOW_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/audio_protocol.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/audio_tick.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/drwav_handle.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/drwav_write_handle.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/alsa_protocol.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/portaudio_protocol.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/dummy_protocol.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/jack_protocol.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/libasound.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/pipewire_protocol.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/portaudio_protocol.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/pulseaudio_protocol.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/jack_protocol.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/sdl_protocol.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/audio/dummy_protocol.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/execution_policy.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/default_policy.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/direct_policy.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/local_state_execution_policy.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/merged_policy.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/ordered_policy.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/priorized_policy.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/to_state_element.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/audio_lock.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/audio_port.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/audio_stretch_mode.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/bench_map.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/dataflow.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/connection.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/control_inlets.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/data.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/value_vector.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/value_port.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/audio_port.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/audio_stretch_mode.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/midi_port.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/data_copy.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/dataflow.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/dataflow_fwd.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution_state.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/exec_state_facade.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/fx_node.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/midi_port.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution_state.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/for_each_port.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/geometry_port.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/graph_edge.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/graph_edge_helpers.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/graph_node.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/node_chain_process.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/node_process.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/port.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/control_inlets.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/sample_to_float.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/float_to_sample.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/timed_value.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/transport.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/typed_value.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/node_chain_process.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/fx_node.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/token_request.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/value_vector.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/value_port.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/nodes/faust/faust_node.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/nodes/faust/faust_utils.hpp" @@ -776,6 +783,7 @@ set(OSSIA_DATAFLOW_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/execution_policy.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/default_policy.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/direct_policy.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/local_state_execution_policy.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/merged_policy.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/ordered_policy.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/priorized_policy.cpp"