diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f8171541..6e68d803 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -219,6 +219,7 @@ target_link_libraries (sfizz_parser PUBLIC absl::strings PRIVATE absl::flat_hash # OSC messaging library set (SFIZZ_MESSAGING_HEADERS sfizz/Messaging.h + sfizz/Messaging.hpp sfizz_message.h) set (SFIZZ_MESSAGING_SOURCES diff --git a/src/sfizz/Messaging.h b/src/sfizz/Messaging.h index 737fa1d4..ab76237f 100644 --- a/src/sfizz/Messaging.h +++ b/src/sfizz/Messaging.h @@ -6,9 +6,14 @@ #pragma once #include "sfizz_message.h" +#include namespace sfz { +template struct OscDataTraits; +template using OscType = typename OscDataTraits::type; +template using OscDecayedType = typename std::decay>::type; + class Client { public: explicit Client(void* data) : data_(data) {} @@ -17,15 +22,18 @@ public: bool canReceive() const { return receive_ != nullptr; } void receive(int delay, const char* path, const char* sig, const sfizz_arg_t* args); + template + void receive(int delay, const char* path, OscDecayedType... values); + +private: + template + sfizz_arg_t make_arg(OscDecayedType value); + private: void* data_ = nullptr; sfizz_receive_t* receive_ = nullptr; }; -inline void Client::receive(int delay, const char* path, const char* sig, const sfizz_arg_t* args) -{ - if (receive_) - receive_(data_, delay, path, sig, args); -} - } // namespace sfz + +#include "Messaging.hpp" diff --git a/src/sfizz/Messaging.hpp b/src/sfizz/Messaging.hpp new file mode 100644 index 00000000..cabd30b6 --- /dev/null +++ b/src/sfizz/Messaging.hpp @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "Messaging.h" +#include +#include + +namespace sfz { + +/// +inline void Client::receive(int delay, const char* path, const char* sig, const sfizz_arg_t* args) +{ + if (receive_) + receive_(data_, delay, path, sig, args); +} + +template +inline void Client::receive(int delay, const char* path, OscDecayedType... values) +{ + constexpr size_t size = sizeof...(Sig); + char sig[size + 1] { Sig..., '\0' }; + sfizz_arg_t args[size] { OscDataTraits::make_arg(values)... }; + receive(delay, path, sig, args); +} + +/// +#define OSC_SCALAR_TRAITS(tag, member) \ + template <> struct OscDataTraits { \ + typedef decltype(sfizz_arg_t::member) type; \ + static_assert(std::is_scalar::value, ""); \ + static inline sfizz_arg_t make_arg(type v) { \ + sfizz_arg_t a; a.member = v; return a; \ + } \ + } +#define OSC_BYTEARRAY_TRAITS(tag, member) \ + template <> struct OscDataTraits { \ + typedef decltype(sfizz_arg_t::member) type; \ + static_assert(std::is_array::value, ""); \ + static inline sfizz_arg_t make_arg(type v) { \ + sfizz_arg_t a; \ + std::memcpy(a.member, v, sizeof(a.member)); \ + return a; \ + } \ + } +#define OSC_VOID_TRAITS(tag) \ + template <> struct OscDataTraits { \ + typedef struct Nothing {} type; \ + static inline sfizz_arg_t make_arg(type v) { \ + sfizz_arg_t a; (void)v; return a; \ + } \ + } + +OSC_SCALAR_TRAITS('i', i); +OSC_SCALAR_TRAITS('c', i); +OSC_SCALAR_TRAITS('r', i); +OSC_BYTEARRAY_TRAITS('m', m); +OSC_SCALAR_TRAITS('h', h); +OSC_SCALAR_TRAITS('f', f); +OSC_SCALAR_TRAITS('d', d); +OSC_SCALAR_TRAITS('s', s); +OSC_SCALAR_TRAITS('S', s); +OSC_SCALAR_TRAITS('b', b); +OSC_VOID_TRAITS('T'); +OSC_VOID_TRAITS('F'); +OSC_VOID_TRAITS('N'); +OSC_VOID_TRAITS('I'); + +#undef OSC_SCALAR_TRAITS +#undef OSC_BYTEARRAY_TRAITS +#undef OSC_VOID_TRAITS + +} // namespace sfz