diff --git a/Makefile.base.mk b/Makefile.base.mk index 2dab4bac..696cdb69 100644 --- a/Makefile.base.mk +++ b/Makefile.base.mk @@ -324,9 +324,9 @@ endif HAVE_LIBLO = $(shell $(PKG_CONFIG) --exists liblo && echo true) -ifeq ($(SKIP_RTAUDIO_FALLBACK),true) -CXXFLAGS += -DDPF_JACK_STANDALONE_SKIP_RTAUDIO_FALLBACK -else +ifneq ($(SKIP_NATIVE_AUDIO_FALLBACK),true) +ifneq ($(SKIP_RTAUDIO_FALLBACK),true) + ifeq ($(MACOS),true) HAVE_RTAUDIO = true else ifeq ($(WINDOWS),true) @@ -334,11 +334,14 @@ HAVE_RTAUDIO = true else HAVE_ALSA = $(shell $(PKG_CONFIG) --exists alsa && echo true) HAVE_PULSEAUDIO = $(shell $(PKG_CONFIG) --exists libpulse-simple && echo true) +HAVE_SDL2 = $(shell $(PKG_CONFIG) --exists sdl2 && echo true) ifeq ($(HAVE_ALSA),true) HAVE_RTAUDIO = true else ifeq ($(HAVE_PULSEAUDIO),true) HAVE_RTAUDIO = true endif +endif + endif endif @@ -466,6 +469,11 @@ PULSEAUDIO_FLAGS = $(shell $(PKG_CONFIG) --cflags libpulse-simple) PULSEAUDIO_LIBS = $(shell $(PKG_CONFIG) --libs libpulse-simple) endif +ifeq ($(HAVE_SDL2),true) +SDL2_FLAGS = $(shell $(PKG_CONFIG) --cflags sdl2) +SDL2_LIBS = $(shell $(PKG_CONFIG) --libs sdl2) +endif + ifeq ($(HAVE_JACK),true) ifeq ($(STATIC_BUILD),true) JACK_FLAGS = $(shell $(PKG_CONFIG) --cflags jack) @@ -627,6 +635,7 @@ features: $(call print_available,HAVE_OPENGL) $(call print_available,HAVE_PULSEAUDIO) $(call print_available,HAVE_RTAUDIO) + $(call print_available,HAVE_SDL2) $(call print_available,HAVE_STUB) $(call print_available,HAVE_VULKAN) $(call print_available,HAVE_X11) diff --git a/Makefile.plugins.mk b/Makefile.plugins.mk index 99fb613a..c848d9d7 100644 --- a/Makefile.plugins.mk +++ b/Makefile.plugins.mk @@ -50,6 +50,14 @@ ifeq ($(HAVE_PULSEAUDIO),true) BASE_FLAGS += -DHAVE_PULSEAUDIO endif +ifeq ($(HAVE_RTAUDIO),true) +BASE_FLAGS += -DHAVE_RTAUDIO +endif + +ifeq ($(HAVE_SDL2),true) +BASE_FLAGS += -DHAVE_SDL2 +endif + # always needed ifneq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true) ifneq ($(STATIC_BUILD),true) @@ -94,6 +102,11 @@ JACK_LIBS += -lpthread endif endif +ifeq ($(HAVE_SDL2),true) +JACK_FLAGS += $(SDL2_FLAGS) +JACK_LIBS += $(SDL2_LIBS) +endif + endif # --------------------------------------------------------------------------------------------------------------------- diff --git a/distrho/extra/RingBuffer.hpp b/distrho/extra/RingBuffer.hpp index 9e80a6be..fc3f0136 100644 --- a/distrho/extra/RingBuffer.hpp +++ b/distrho/extra/RingBuffer.hpp @@ -203,11 +203,23 @@ public: /* * Get the size of the data available to read. */ - uint32_t getAvailableDataSize() const noexcept + uint32_t getReadableDataSize() const noexcept { DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, 0); - const uint32_t wrap((buffer->tail > buffer->wrtn) ? 0 : buffer->size); + const uint32_t wrap = buffer->head > buffer->tail ? 0 : buffer->size; + + return wrap + buffer->head - buffer->tail; + } + + /* + * Get the size of the data available to write. + */ + uint32_t getWritableDataSize() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, 0); + + const uint32_t wrap = (buffer->tail > buffer->wrtn) ? 0 : buffer->size; return wrap + buffer->tail - buffer->wrtn; } @@ -724,6 +736,15 @@ public: heapBuffer.size = 0; } + void copyFromAndClearOther(HeapRingBuffer& other) + { + DISTRHO_SAFE_ASSERT_RETURN(other.heapBuffer.size == heapBuffer.size,); + + std::memcpy(&heapBuffer, &other.heapBuffer, sizeof(HeapBuffer) - sizeof(uint8_t*)); + std::memcpy(heapBuffer.buf, other.heapBuffer.buf, sizeof(uint8_t) * heapBuffer.size); + other.clearData(); + } + private: /** The heap buffer used for this class. */ HeapBuffer heapBuffer; diff --git a/distrho/src/jackbridge/JackBridge.cpp b/distrho/src/jackbridge/JackBridge.cpp index 97987052..f5fb3229 100644 --- a/distrho/src/jackbridge/JackBridge.cpp +++ b/distrho/src/jackbridge/JackBridge.cpp @@ -35,16 +35,24 @@ #include #include "../../extra/LibraryUtils.hpp" -// in case JACK fails, we fallback to RtAudio or SDL native API -#if defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_WASM) -# include "SDLBridge.hpp" -#elif defined(DISTRHO_PROPER_CPP11_SUPPORT) && !defined(DPF_JACK_STANDALONE_SKIP_RTAUDIO_FALLBACK) +// in case JACK fails, we fallback to native bridges simulating JACK API +#include "NativeBridge.hpp" + +#if defined(DISTRHO_OS_WASM) +# include "WebBridge.hpp" +#endif + +#if defined(HAVE_RTAUDIO) && DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 # include "RtAudioBridge.hpp" # ifdef RTAUDIO_API_TYPE # include "rtaudio/RtAudio.cpp" # endif #endif +#if defined(HAVE_SDL2) && DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 +# include "SDL2Bridge.hpp" +#endif + // ----------------------------------------------------------------------------- extern "C" { @@ -314,14 +322,6 @@ struct JackBridge { jacksym_set_thread_creator set_thread_creator_ptr; #endif - static bool usingRtAudioOrSDL; -#ifdef DISTRHO_OS_WASM - static SDLBridge sdl; -#endif -#ifdef RTAUDIO_API_TYPE - static RtAudioBridge rtAudio; -#endif - JackBridge() : lib(nullptr), get_version_ptr(nullptr), @@ -420,18 +420,21 @@ struct JackBridge { , set_thread_creator_ptr(nullptr) #endif { -# ifdef DISTRHO_OS_WASM + #ifdef DISTRHO_OS_WASM + // never use jack in wasm return; -# endif -# if defined(DISTRHO_OS_MAC) - const char* const filename("libjack.dylib"); -# elif defined(DISTRHO_OS_WINDOWS) && defined(_WIN64) - const char* const filename("libjack64.dll"); -# elif defined(DISTRHO_OS_WINDOWS) - const char* const filename("libjack.dll"); -# else - const char* const filename("libjack.so.0"); -# endif + #endif + + #if defined(DISTRHO_OS_MAC) + const char* const filename = "libjack.dylib"; + #elif defined(DISTRHO_OS_WINDOWS) && defined(_WIN64) + const char* const filename = "libjack64.dll"; + #elif defined(DISTRHO_OS_WINDOWS) + const char* const filename = "libjack.dll"; + #else + const char* const filename = "libjack.so.0"; + #endif + USE_NAMESPACE_DISTRHO lib = lib_open(filename); @@ -584,13 +587,9 @@ struct JackBridge { DISTRHO_DECLARE_NON_COPYABLE(JackBridge); }; -bool JackBridge::usingRtAudioOrSDL = false; -#ifdef DISTRHO_OS_WASM -SDLBridge JackBridge::sdl; -#endif -#ifdef RTAUDIO_API_TYPE -RtAudioBridge JackBridge::rtAudio; -#endif +static bool usingNativeBridge = false; +static bool usingRealJACK = true; +static NativeBridge* nativeBridge = nullptr; // ----------------------------------------------------------------------------- @@ -842,9 +841,8 @@ void jackbridge_get_version(int* major_ptr, int* minor_ptr, int* micro_ptr, int* #elif defined(JACKBRIDGE_DIRECT) return jack_get_version(major_ptr, minor_ptr, micro_ptr, proto_ptr); #else - if (! JackBridge::usingRtAudioOrSDL) - if (getBridgeInstance().get_version_ptr != nullptr) - return getBridgeInstance().get_version_ptr(major_ptr, minor_ptr, micro_ptr, proto_ptr); + if (usingRealJACK && getBridgeInstance().get_version_ptr != nullptr) + return getBridgeInstance().get_version_ptr(major_ptr, minor_ptr, micro_ptr, proto_ptr); #endif if (major_ptr != nullptr) *major_ptr = 0; @@ -862,15 +860,7 @@ const char* jackbridge_get_version_string() #elif defined(JACKBRIDGE_DIRECT) return jack_get_version_string(); #else -# ifdef DISTRHO_OS_WASM - if (JackBridge::usingRtAudioOrSDL) - return "2"; // SDL_VERSION; -# endif -# ifdef RTAUDIO_API_TYPE - if (JackBridge::usingRtAudioOrSDL) - return RTAUDIO_VERSION; -# endif - if (getBridgeInstance().get_version_string_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().get_version_string_ptr != nullptr) return getBridgeInstance().get_version_string_ptr(); #endif return nullptr; @@ -884,30 +874,40 @@ jack_client_t* jackbridge_client_open(const char* client_name, uint32_t options, #elif defined(JACKBRIDGE_DIRECT) return jack_client_open(client_name, static_cast(options), status); #else -# ifdef DISTRHO_OS_WASM - if (JackBridge::sdl.open(client_name)) - { - d_stdout("SDL audio setup ok"); - JackBridge::usingRtAudioOrSDL = true; - return (jack_client_t*)0x1; // return non-null - // unused - (void)options; - } - d_stderr2("SDL audio setup failed"); -# else + #ifndef DISTRHO_OS_WASM if (getBridgeInstance().client_open_ptr != nullptr) if (jack_client_t* const client = getBridgeInstance().client_open_ptr(client_name, static_cast(options), status)) return client; - // TODO -# endif -# ifdef RTAUDIO_API_TYPE - if (JackBridge::rtAudio.open()) - { - d_stdout("JACK setup failed, using RtAudio instead"); - JackBridge::usingRtAudioOrSDL = true; - return (jack_client_t*)0x1; // return non-null - } -# endif + #endif + + static jack_client_t* const kValidClient = (jack_client_t*)0x1; + + // maybe unused + (void)kValidClient; + + usingNativeBridge = true; + usingRealJACK = false; + + #ifdef DISTRHO_OS_WASM + nativeBridge = new WebBridge; + if (nativeBridge->open(client_name)) + return kValidClient; + delete nativeBridge; + #endif + + #if defined(HAVE_RTAUDIO) && defined(RTAUDIO_API_TYPE) + nativeBridge = new RtAudioBridge; + if (nativeBridge->open(client_name)) + return kValidClient; + delete nativeBridge; + #endif + + #if defined(HAVE_SDL2) && DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + nativeBridge = new SDL2Bridge; + if (nativeBridge->open(client_name)) + return kValidClient; + delete nativeBridge; + #endif #endif if (status != nullptr) *status = JackServerError; @@ -920,15 +920,17 @@ bool jackbridge_client_close(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_client_close(client) == 0); #else - if (JackBridge::usingRtAudioOrSDL) + if (usingNativeBridge) { - JackBridge::usingRtAudioOrSDL = false; -# ifdef DISTRHO_OS_WASM - return JackBridge::sdl.close(); -# endif -# ifdef RTAUDIO_API_TYPE - return JackBridge::rtAudio.close(); -# endif + if (nativeBridge != nullptr) + { + nativeBridge->close(); + delete nativeBridge; + nativeBridge = nullptr; + } + usingNativeBridge = false; + usingRealJACK = true; + return true; } if (getBridgeInstance().client_close_ptr != nullptr) return (getBridgeInstance().client_close_ptr(client) == 0); @@ -944,9 +946,8 @@ int jackbridge_client_name_size() #elif defined(JACKBRIDGE_DIRECT) return jack_client_name_size(); #else - if (! JackBridge::usingRtAudioOrSDL) - if (getBridgeInstance().client_name_size_ptr != nullptr) - return getBridgeInstance().client_name_size_ptr(); + if (usingRealJACK && getBridgeInstance().client_name_size_ptr != nullptr) + return getBridgeInstance().client_name_size_ptr(); #endif return 33; } @@ -957,11 +958,8 @@ const char* jackbridge_get_client_name(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_get_client_name(client); #else - if (JackBridge::usingRtAudioOrSDL) - { - static const char* const name = DISTRHO_PLUGIN_NAME; - return name; - } + if (usingNativeBridge) + return DISTRHO_PLUGIN_NAME; if (getBridgeInstance().get_client_name_ptr != nullptr) return getBridgeInstance().get_client_name_ptr(client); #endif @@ -976,7 +974,7 @@ char* jackbridge_client_get_uuid(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_client_get_uuid(client); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (const jacksym_client_get_uuid func = getBridgeInstance().client_get_uuid_ptr) return func(client); #endif @@ -989,7 +987,7 @@ char* jackbridge_get_uuid_for_client_name(jack_client_t* client, const char* nam #elif defined(JACKBRIDGE_DIRECT) return jack_get_uuid_for_client_name(client, name); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().get_uuid_for_client_name_ptr != nullptr) return getBridgeInstance().get_uuid_for_client_name_ptr(client, name); #endif @@ -1002,7 +1000,7 @@ char* jackbridge_get_client_name_by_uuid(jack_client_t* client, const char* uuid #elif defined(JACKBRIDGE_DIRECT) return jack_get_client_name_by_uuid(client, uuid); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().get_client_name_by_uuid_ptr != nullptr) return getBridgeInstance().get_client_name_by_uuid_ptr(client, uuid); #endif @@ -1017,7 +1015,7 @@ bool jackbridge_uuid_parse(const char* buf, jack_uuid_t* uuid) #elif defined(JACKBRIDGE_DIRECT) return (jack_uuid_parse(buf, uuid) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (const jacksym_uuid_parse func = getBridgeInstance().uuid_parse_ptr) return (func(buf, uuid) == 0); #endif @@ -1030,7 +1028,7 @@ void jackbridge_uuid_unparse(jack_uuid_t uuid, char buf[JACK_UUID_STRING_SIZE]) #elif defined(JACKBRIDGE_DIRECT) jack_uuid_unparse(uuid, buf); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (const jacksym_uuid_unparse func = getBridgeInstance().uuid_unparse_ptr) return func(uuid, buf); #endif @@ -1044,15 +1042,8 @@ bool jackbridge_activate(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_activate(client) == 0); #else - if (JackBridge::usingRtAudioOrSDL) - { -# ifdef DISTRHO_OS_WASM - return JackBridge::sdl.activate(); -# endif -# ifdef RTAUDIO_API_TYPE - return JackBridge::rtAudio.activate(); -# endif - } + if (usingNativeBridge) + return nativeBridge->activate(); if (getBridgeInstance().activate_ptr != nullptr) return (getBridgeInstance().activate_ptr(client) == 0); #endif @@ -1065,15 +1056,8 @@ bool jackbridge_deactivate(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_deactivate(client) == 0); #else - if (JackBridge::usingRtAudioOrSDL) - { -# ifdef DISTRHO_OS_WASM - return JackBridge::sdl.deactivate(); -# endif -# ifdef RTAUDIO_API_TYPE - return JackBridge::rtAudio.deactivate(); -# endif - } + if (usingNativeBridge) + return nativeBridge->deactivate(); if (getBridgeInstance().deactivate_ptr != nullptr) return (getBridgeInstance().deactivate_ptr(client) == 0); #endif @@ -1086,7 +1070,7 @@ bool jackbridge_is_realtime(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_is_realtime(client); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().is_realtime_ptr != nullptr) return getBridgeInstance().is_realtime_ptr(client); #endif @@ -1101,7 +1085,7 @@ bool jackbridge_set_thread_init_callback(jack_client_t* client, JackThreadInitCa #elif defined(JACKBRIDGE_DIRECT) return (jack_set_thread_init_callback(client, thread_init_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_thread_init_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_thread_init_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_thread_init(thread_init_callback); @@ -1120,7 +1104,7 @@ void jackbridge_on_shutdown(jack_client_t* client, JackShutdownCallback shutdown #elif defined(JACKBRIDGE_DIRECT) jack_on_shutdown(client, shutdown_callback, arg); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().on_shutdown_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().on_shutdown_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_shutdown(shutdown_callback); @@ -1138,7 +1122,7 @@ void jackbridge_on_info_shutdown(jack_client_t* client, JackInfoShutdownCallback #elif defined(JACKBRIDGE_DIRECT) jack_on_info_shutdown(client, shutdown_callback, arg); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().on_info_shutdown_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().on_info_shutdown_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_info_shutdown(shutdown_callback); @@ -1156,18 +1140,11 @@ bool jackbridge_set_process_callback(jack_client_t* client, JackProcessCallback #elif defined(JACKBRIDGE_DIRECT) return (jack_set_process_callback(client, process_callback, arg) == 0); #else - if (JackBridge::usingRtAudioOrSDL) + if (usingNativeBridge) { -# ifdef DISTRHO_OS_WASM - JackBridge::sdl.jackProcessCallback = process_callback; - JackBridge::sdl.jackProcessArg = arg; + nativeBridge->jackProcessCallback = process_callback; + nativeBridge->jackProcessArg = arg; return true; -# endif -# ifdef RTAUDIO_API_TYPE - JackBridge::rtAudio.jackProcessCallback = process_callback; - JackBridge::rtAudio.jackProcessArg = arg; - return true; -# endif } if (getBridgeInstance().set_process_callback_ptr != nullptr) { @@ -1188,7 +1165,7 @@ bool jackbridge_set_freewheel_callback(jack_client_t* client, JackFreewheelCallb #elif defined(JACKBRIDGE_DIRECT) return (jack_set_freewheel_callback(client, freewheel_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_freewheel_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_freewheel_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_freewheel(freewheel_callback); @@ -1207,7 +1184,7 @@ bool jackbridge_set_buffer_size_callback(jack_client_t* client, JackBufferSizeCa #elif defined(JACKBRIDGE_DIRECT) return (jack_set_buffer_size_callback(client, bufsize_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_buffer_size_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_buffer_size_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_bufsize(bufsize_callback); @@ -1226,7 +1203,7 @@ bool jackbridge_set_sample_rate_callback(jack_client_t* client, JackSampleRateCa #elif defined(JACKBRIDGE_DIRECT) return (jack_set_sample_rate_callback(client, srate_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_sample_rate_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_sample_rate_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_srate(srate_callback); @@ -1245,7 +1222,7 @@ bool jackbridge_set_client_registration_callback(jack_client_t* client, JackClie #elif defined(JACKBRIDGE_DIRECT) return (jack_set_client_registration_callback(client, registration_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_client_registration_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_client_registration_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_client_reg(registration_callback); @@ -1264,7 +1241,7 @@ bool jackbridge_set_port_registration_callback(jack_client_t* client, JackPortRe #elif defined(JACKBRIDGE_DIRECT) return (jack_set_port_registration_callback(client, registration_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_port_registration_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_port_registration_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_port_reg(registration_callback); @@ -1283,7 +1260,7 @@ bool jackbridge_set_port_rename_callback(jack_client_t* client, JackPortRenameCa #elif defined(JACKBRIDGE_DIRECT) return (jack_set_port_rename_callback(client, rename_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_port_rename_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_port_rename_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_port_rename(rename_callback); @@ -1302,7 +1279,7 @@ bool jackbridge_set_port_connect_callback(jack_client_t* client, JackPortConnect #elif defined(JACKBRIDGE_DIRECT) return (jack_set_port_connect_callback(client, connect_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_port_connect_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_port_connect_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_port_conn(connect_callback); @@ -1321,7 +1298,7 @@ bool jackbridge_set_graph_order_callback(jack_client_t* client, JackGraphOrderCa #elif defined(JACKBRIDGE_DIRECT) return (jack_set_graph_order_callback(client, graph_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_graph_order_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_graph_order_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_graph_order(graph_callback); @@ -1340,7 +1317,7 @@ bool jackbridge_set_xrun_callback(jack_client_t* client, JackXRunCallback xrun_c #elif defined(JACKBRIDGE_DIRECT) return (jack_set_xrun_callback(client, xrun_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_xrun_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_xrun_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_xrun(xrun_callback); @@ -1359,7 +1336,7 @@ bool jackbridge_set_latency_callback(jack_client_t* client, JackLatencyCallback #elif defined(JACKBRIDGE_DIRECT) return (jack_set_latency_callback(client, latency_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_latency_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_latency_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_latency(latency_callback); @@ -1380,7 +1357,7 @@ bool jackbridge_set_freewheel(jack_client_t* client, bool onoff) #elif defined(JACKBRIDGE_DIRECT) return jack_set_freewheel(client, onoff); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().set_freewheel_ptr != nullptr) return getBridgeInstance().set_freewheel_ptr(client, onoff); #endif @@ -1393,7 +1370,7 @@ bool jackbridge_set_buffer_size(jack_client_t* client, jack_nframes_t nframes) #elif defined(JACKBRIDGE_DIRECT) return jack_set_buffer_size(client, nframes); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().set_buffer_size_ptr != nullptr) return getBridgeInstance().set_buffer_size_ptr(client, nframes); #endif @@ -1408,15 +1385,8 @@ jack_nframes_t jackbridge_get_sample_rate(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_get_sample_rate(client); #else - if (JackBridge::usingRtAudioOrSDL) - { -# ifdef DISTRHO_OS_WASM - return JackBridge::sdl.sampleRate; -# endif -# ifdef RTAUDIO_API_TYPE - return JackBridge::rtAudio.sampleRate; -# endif - } + if (usingNativeBridge) + return nativeBridge->sampleRate; if (getBridgeInstance().get_sample_rate_ptr != nullptr) return getBridgeInstance().get_sample_rate_ptr(client); #endif @@ -1429,15 +1399,8 @@ jack_nframes_t jackbridge_get_buffer_size(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_get_buffer_size(client); #else - if (JackBridge::usingRtAudioOrSDL) - { -# ifdef DISTRHO_OS_WASM - return JackBridge::sdl.bufferSize; -# endif -# ifdef RTAUDIO_API_TYPE - return JackBridge::rtAudio.bufferSize; -# endif - } + if (usingNativeBridge) + return nativeBridge->bufferSize; if (getBridgeInstance().get_buffer_size_ptr != nullptr) return getBridgeInstance().get_buffer_size_ptr(client); #endif @@ -1450,7 +1413,7 @@ float jackbridge_cpu_load(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_cpu_load(client); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().cpu_load_ptr != nullptr) return getBridgeInstance().cpu_load_ptr(client); #endif @@ -1465,15 +1428,8 @@ jack_port_t* jackbridge_port_register(jack_client_t* client, const char* port_na #elif defined(JACKBRIDGE_DIRECT) return jack_port_register(client, port_name, type, flags, buffer_size); #else - if (JackBridge::usingRtAudioOrSDL) - { -# ifdef DISTRHO_OS_WASM - return JackBridge::sdl.registerPort(type, flags); -# endif -# ifdef RTAUDIO_API_TYPE - return JackBridge::rtAudio.registerPort(type, flags); -# endif - } + if (usingNativeBridge) + return nativeBridge->registerPort(type, flags); if (getBridgeInstance().port_register_ptr != nullptr) return getBridgeInstance().port_register_ptr(client, port_name, type, static_cast(flags), @@ -1488,7 +1444,7 @@ bool jackbridge_port_unregister(jack_client_t* client, jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_unregister(client, port) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_unregister_ptr != nullptr) return (getBridgeInstance().port_unregister_ptr(client, port) == 0); #endif @@ -1501,15 +1457,8 @@ void* jackbridge_port_get_buffer(jack_port_t* port, jack_nframes_t nframes) #elif defined(JACKBRIDGE_DIRECT) return jack_port_get_buffer(port, nframes); #else - if (JackBridge::usingRtAudioOrSDL) - { -# ifdef DISTRHO_OS_WASM - return JackBridge::sdl.getPortBuffer(port); -# endif -# ifdef RTAUDIO_API_TYPE - return JackBridge::rtAudio.getPortBuffer(port); -# endif - } + if (usingNativeBridge) + return nativeBridge->getPortBuffer(port); if (getBridgeInstance().port_get_buffer_ptr != nullptr) return getBridgeInstance().port_get_buffer_ptr(port, nframes); #endif @@ -1524,7 +1473,7 @@ const char* jackbridge_port_name(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_name(port); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_name_ptr != nullptr) return getBridgeInstance().port_name_ptr(port); #endif @@ -1537,7 +1486,7 @@ jack_uuid_t jackbridge_port_uuid(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_uuid(port); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_uuid_ptr != nullptr) return getBridgeInstance().port_uuid_ptr(port); #endif @@ -1550,7 +1499,7 @@ const char* jackbridge_port_short_name(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_short_name(port); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_short_name_ptr != nullptr) return getBridgeInstance().port_short_name_ptr(port); #endif @@ -1563,7 +1512,7 @@ int jackbridge_port_flags(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_flags(port); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_flags_ptr != nullptr) return getBridgeInstance().port_flags_ptr(port); #endif @@ -1576,7 +1525,7 @@ const char* jackbridge_port_type(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_type(port); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_type_ptr != nullptr) return getBridgeInstance().port_type_ptr(port); #endif @@ -1589,7 +1538,7 @@ bool jackbridge_port_is_mine(const jack_client_t* client, const jack_port_t* por #elif defined(JACKBRIDGE_DIRECT) return jack_port_is_mine(client, port); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_is_mine_ptr != nullptr) return getBridgeInstance().port_is_mine_ptr(client, port); #endif @@ -1602,7 +1551,7 @@ int jackbridge_port_connected(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_connected(port); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_connected_ptr != nullptr) return getBridgeInstance().port_connected_ptr(port); #endif @@ -1615,7 +1564,7 @@ bool jackbridge_port_connected_to(const jack_port_t* port, const char* port_name #elif defined(JACKBRIDGE_DIRECT) return jack_port_connected_to(port, port_name); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_connected_to_ptr != nullptr) return getBridgeInstance().port_connected_to_ptr(port, port_name); #endif @@ -1628,7 +1577,7 @@ const char** jackbridge_port_get_connections(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_get_connections(port); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_get_connections_ptr != nullptr) return getBridgeInstance().port_get_connections_ptr(port); #endif @@ -1641,7 +1590,7 @@ const char** jackbridge_port_get_all_connections(const jack_client_t* client, co #elif defined(JACKBRIDGE_DIRECT) return jack_port_get_all_connections(client, port); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_get_all_connections_ptr != nullptr) return getBridgeInstance().port_get_all_connections_ptr(client, port); #endif @@ -1656,7 +1605,7 @@ bool jackbridge_port_rename(jack_client_t* client, jack_port_t* port, const char #elif defined(JACKBRIDGE_DIRECT) return (jack_port_rename(client, port, port_name) == 0); #else - if (JackBridge::usingRtAudioOrSDL) + if (usingNativeBridge) return false; // Try new API first if (getBridgeInstance().port_rename_ptr != nullptr) @@ -1674,7 +1623,7 @@ bool jackbridge_port_set_alias(jack_port_t* port, const char* alias) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_set_alias(port, alias) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_set_alias_ptr != nullptr) return (getBridgeInstance().port_set_alias_ptr(port, alias) == 0); #endif @@ -1687,7 +1636,7 @@ bool jackbridge_port_unset_alias(jack_port_t* port, const char* alias) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_unset_alias(port, alias) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_unset_alias_ptr != nullptr) return (getBridgeInstance().port_unset_alias_ptr(port, alias) == 0); #endif @@ -1700,7 +1649,7 @@ int jackbridge_port_get_aliases(const jack_port_t* port, char* const aliases[2]) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_get_aliases(port, aliases) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_get_aliases_ptr != nullptr) return getBridgeInstance().port_get_aliases_ptr(port, aliases); #endif @@ -1715,7 +1664,7 @@ bool jackbridge_port_request_monitor(jack_port_t* port, bool onoff) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_request_monitor(port, onoff) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_request_monitor_ptr != nullptr) return (getBridgeInstance().port_request_monitor_ptr(port, onoff) == 0); #endif @@ -1728,7 +1677,7 @@ bool jackbridge_port_request_monitor_by_name(jack_client_t* client, const char* #elif defined(JACKBRIDGE_DIRECT) return (jack_port_request_monitor_by_name(client, port_name, onoff) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_request_monitor_by_name_ptr != nullptr) return (getBridgeInstance().port_request_monitor_by_name_ptr(client, port_name, onoff) == 0); #endif @@ -1741,7 +1690,7 @@ bool jackbridge_port_ensure_monitor(jack_port_t* port, bool onoff) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_ensure_monitor(port, onoff) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_ensure_monitor_ptr != nullptr) return (getBridgeInstance().port_ensure_monitor_ptr(port, onoff) == 0); #endif @@ -1754,7 +1703,7 @@ bool jackbridge_port_monitoring_input(jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_monitoring_input(port); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_monitoring_input_ptr != nullptr) return getBridgeInstance().port_monitoring_input_ptr(port); #endif @@ -1769,7 +1718,7 @@ bool jackbridge_connect(jack_client_t* client, const char* source_port, const ch #elif defined(JACKBRIDGE_DIRECT) return (jack_connect(client, source_port, destination_port) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().connect_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().connect_ptr != nullptr) { const int ret = getBridgeInstance().connect_ptr(client, source_port, destination_port); return ret == 0 || ret == EEXIST; @@ -1784,7 +1733,7 @@ bool jackbridge_disconnect(jack_client_t* client, const char* source_port, const #elif defined(JACKBRIDGE_DIRECT) return (jack_disconnect(client, source_port, destination_port) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().disconnect_ptr != nullptr) return (getBridgeInstance().disconnect_ptr(client, source_port, destination_port) == 0); #endif @@ -1797,7 +1746,7 @@ bool jackbridge_port_disconnect(jack_client_t* client, jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_disconnect(client, port) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_disconnect_ptr != nullptr) return (getBridgeInstance().port_disconnect_ptr(client, port) == 0); #endif @@ -1812,7 +1761,7 @@ int jackbridge_port_name_size() #elif defined(JACKBRIDGE_DIRECT) return jack_port_name_size(); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_name_size_ptr != nullptr) return getBridgeInstance().port_name_size_ptr(); #endif @@ -1825,7 +1774,7 @@ int jackbridge_port_type_size() #elif defined(JACKBRIDGE_DIRECT) return jack_port_type_size(); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_type_size_ptr != nullptr) return getBridgeInstance().port_type_size_ptr(); #endif @@ -1838,7 +1787,7 @@ uint32_t jackbridge_port_type_get_buffer_size(jack_client_t* client, const char* #elif defined(JACKBRIDGE_DIRECT) return static_cast(jack_port_type_get_buffer_size(client, port_type)); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_type_get_buffer_size_ptr != nullptr) return static_cast(getBridgeInstance().port_type_get_buffer_size_ptr(client, port_type)); #endif @@ -1853,7 +1802,7 @@ void jackbridge_port_get_latency_range(jack_port_t* port, uint32_t mode, jack_la #elif defined(JACKBRIDGE_DIRECT) return jack_port_get_latency_range(port, static_cast(mode), range); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_get_latency_range_ptr != nullptr) return getBridgeInstance().port_get_latency_range_ptr(port, static_cast(mode), @@ -1869,7 +1818,7 @@ void jackbridge_port_set_latency_range(jack_port_t* port, uint32_t mode, jack_la #elif defined(JACKBRIDGE_DIRECT) jack_port_set_latency_range(port, static_cast(mode), range); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_set_latency_range_ptr != nullptr) getBridgeInstance().port_set_latency_range_ptr(port, static_cast(mode), @@ -1883,7 +1832,7 @@ bool jackbridge_recompute_total_latencies(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_recompute_total_latencies(client) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().recompute_total_latencies_ptr != nullptr) return (getBridgeInstance().recompute_total_latencies_ptr(client) == 0); #endif @@ -1898,7 +1847,7 @@ const char** jackbridge_get_ports(jack_client_t* client, const char* port_name_p #elif defined(JACKBRIDGE_DIRECT) return jack_get_ports(client, port_name_pattern, type_name_pattern, flags); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().get_ports_ptr != nullptr) return getBridgeInstance().get_ports_ptr(client, port_name_pattern, type_name_pattern, static_cast(flags)); @@ -1912,7 +1861,7 @@ jack_port_t* jackbridge_port_by_name(jack_client_t* client, const char* port_nam #elif defined(JACKBRIDGE_DIRECT) return jack_port_by_name(client, port_name); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_by_name_ptr != nullptr) return getBridgeInstance().port_by_name_ptr(client, port_name); #endif @@ -1925,7 +1874,7 @@ jack_port_t* jackbridge_port_by_id(jack_client_t* client, jack_port_id_t port_id #elif defined(JACKBRIDGE_DIRECT) return jack_port_by_id(client, port_id); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().port_by_id_ptr != nullptr) return getBridgeInstance().port_by_id_ptr(client, port_id); #endif @@ -1940,7 +1889,7 @@ void jackbridge_free(void* ptr) #elif defined(JACKBRIDGE_DIRECT) return jack_free(ptr); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().free_ptr != nullptr) return getBridgeInstance().free_ptr(ptr); @@ -1957,9 +1906,10 @@ uint32_t jackbridge_midi_get_event_count(void* port_buffer) #elif defined(JACKBRIDGE_DIRECT) return jack_midi_get_event_count(port_buffer); #else - if (! JackBridge::usingRtAudioOrSDL) - if (getBridgeInstance().midi_get_event_count_ptr != nullptr) - return getBridgeInstance().midi_get_event_count_ptr(port_buffer); + if (usingNativeBridge) + return nativeBridge->getEventCount(); + if (getBridgeInstance().midi_get_event_count_ptr != nullptr) + return getBridgeInstance().midi_get_event_count_ptr(port_buffer); #endif return 0; } @@ -1970,9 +1920,10 @@ bool jackbridge_midi_event_get(jack_midi_event_t* event, void* port_buffer, uint #elif defined(JACKBRIDGE_DIRECT) return (jack_midi_event_get(event, port_buffer, event_index) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) - if (getBridgeInstance().midi_event_get_ptr != nullptr) - return (getBridgeInstance().midi_event_get_ptr(event, port_buffer, event_index) == 0); + if (usingNativeBridge) + return nativeBridge->getEvent(event); + if (getBridgeInstance().midi_event_get_ptr != nullptr) + return (getBridgeInstance().midi_event_get_ptr(event, port_buffer, event_index) == 0); #endif return false; } @@ -1983,9 +1934,10 @@ void jackbridge_midi_clear_buffer(void* port_buffer) #elif defined(JACKBRIDGE_DIRECT) jack_midi_clear_buffer(port_buffer); #else - if (! JackBridge::usingRtAudioOrSDL) - if (getBridgeInstance().midi_clear_buffer_ptr != nullptr) - getBridgeInstance().midi_clear_buffer_ptr(port_buffer); + if (usingNativeBridge) + return nativeBridge->clearEventBuffer(); + if (getBridgeInstance().midi_clear_buffer_ptr != nullptr) + getBridgeInstance().midi_clear_buffer_ptr(port_buffer); #endif } @@ -1995,9 +1947,10 @@ bool jackbridge_midi_event_write(void* port_buffer, jack_nframes_t time, const j #elif defined(JACKBRIDGE_DIRECT) return (jack_midi_event_write(port_buffer, time, data, data_size) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) - if (getBridgeInstance().midi_event_write_ptr != nullptr) - return (getBridgeInstance().midi_event_write_ptr(port_buffer, time, data, data_size) == 0); + if (usingNativeBridge) + return nativeBridge->writeEvent(time, data, data_size); + if (getBridgeInstance().midi_event_write_ptr != nullptr) + return (getBridgeInstance().midi_event_write_ptr(port_buffer, time, data, data_size) == 0); #endif return false; } @@ -2008,7 +1961,7 @@ jack_midi_data_t* jackbridge_midi_event_reserve(void* port_buffer, jack_nframes_ #elif defined(JACKBRIDGE_DIRECT) return jack_midi_event_reserve(port_buffer, time, data_size); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().midi_event_reserve_ptr != nullptr) return getBridgeInstance().midi_event_reserve_ptr(port_buffer, time, data_size); #endif @@ -2023,7 +1976,7 @@ bool jackbridge_release_timebase(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_release_timebase(client) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().release_timebase_ptr != nullptr) return (getBridgeInstance().release_timebase_ptr(client) == 0); #endif @@ -2036,7 +1989,7 @@ bool jackbridge_set_sync_callback(jack_client_t* client, JackSyncCallback sync_c #elif defined(JACKBRIDGE_DIRECT) return (jack_set_sync_callback(client, sync_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_sync_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_sync_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_sync(sync_callback); @@ -2055,7 +2008,7 @@ bool jackbridge_set_sync_timeout(jack_client_t* client, jack_time_t timeout) #elif defined(JACKBRIDGE_DIRECT) return (jack_set_sync_timeout(client, timeout) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().set_sync_timeout_ptr != nullptr) return (getBridgeInstance().set_sync_timeout_ptr(client, timeout) == 0); #endif @@ -2068,7 +2021,7 @@ bool jackbridge_set_timebase_callback(jack_client_t* client, bool conditional, J #elif defined(JACKBRIDGE_DIRECT) return (jack_set_timebase_callback(client, conditional, timebase_callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_timebase_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_timebase_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_timebase(timebase_callback); @@ -2087,7 +2040,7 @@ bool jackbridge_transport_locate(jack_client_t* client, jack_nframes_t frame) #elif defined(JACKBRIDGE_DIRECT) return (jack_transport_locate(client, frame) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().transport_locate_ptr != nullptr) return (getBridgeInstance().transport_locate_ptr(client, frame) == 0); #endif @@ -2100,7 +2053,7 @@ uint32_t jackbridge_transport_query(const jack_client_t* client, jack_position_t #elif defined(JACKBRIDGE_DIRECT) return jack_transport_query(client, pos); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().transport_query_ptr != nullptr) return getBridgeInstance().transport_query_ptr(client, pos); #endif @@ -2120,7 +2073,7 @@ jack_nframes_t jackbridge_get_current_transport_frame(const jack_client_t* clien #elif defined(JACKBRIDGE_DIRECT) return jack_get_current_transport_frame(client); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().get_current_transport_frame_ptr != nullptr) return getBridgeInstance().get_current_transport_frame_ptr(client); #endif @@ -2133,7 +2086,7 @@ bool jackbridge_transport_reposition(jack_client_t* client, const jack_position_ #elif defined(JACKBRIDGE_DIRECT) return (jack_transport_reposition(client, pos) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().transport_reposition_ptr != nullptr) return (getBridgeInstance().transport_reposition_ptr(client, pos) == 0); #endif @@ -2146,7 +2099,7 @@ void jackbridge_transport_start(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) jack_transport_start(client); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().transport_start_ptr != nullptr) getBridgeInstance().transport_start_ptr(client); #endif @@ -2158,7 +2111,7 @@ void jackbridge_transport_stop(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) jack_transport_stop(client); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().transport_stop_ptr != nullptr) getBridgeInstance().transport_stop_ptr(client); #endif @@ -2172,7 +2125,7 @@ bool jackbridge_set_property(jack_client_t* client, jack_uuid_t subject, const c #elif defined(JACKBRIDGE_DIRECT) return (jack_set_property(client, subject, key, value, type) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().set_property_ptr != nullptr) return (getBridgeInstance().set_property_ptr(client, subject, key, value, type) == 0); #endif @@ -2185,7 +2138,7 @@ bool jackbridge_get_property(jack_uuid_t subject, const char* key, char** value, #elif defined(JACKBRIDGE_DIRECT) return (jack_get_property(subject, key, value, type) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().get_property_ptr != nullptr) return (getBridgeInstance().get_property_ptr(subject, key, value, type) == 0); #endif @@ -2198,7 +2151,7 @@ void jackbridge_free_description(jack_description_t* desc, bool free_description #elif defined(JACKBRIDGE_DIRECT) jack_free_description(desc, free_description_itself); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().free_description_ptr != nullptr) getBridgeInstance().free_description_ptr(desc, free_description_itself); #endif @@ -2210,7 +2163,7 @@ bool jackbridge_get_properties(jack_uuid_t subject, jack_description_t* desc) #elif defined(JACKBRIDGE_DIRECT) return (jack_get_properties(subject, desc) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().get_properties_ptr != nullptr) return (getBridgeInstance().get_properties_ptr(subject, desc) == 0); #endif @@ -2223,7 +2176,7 @@ bool jackbridge_get_all_properties(jack_description_t** descs) #elif defined(JACKBRIDGE_DIRECT) return (jack_get_all_properties(descs) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().get_all_properties_ptr != nullptr) return (getBridgeInstance().get_all_properties_ptr(descs) == 0); #endif @@ -2236,7 +2189,7 @@ bool jackbridge_remove_property(jack_client_t* client, jack_uuid_t subject, cons #elif defined(JACKBRIDGE_DIRECT) return (jack_remove_property(client, subject, key) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().remove_property_ptr != nullptr) return (getBridgeInstance().remove_property_ptr(client, subject, key) == 0); #endif @@ -2249,7 +2202,7 @@ int jackbridge_remove_properties(jack_client_t* client, jack_uuid_t subject) #elif defined(JACKBRIDGE_DIRECT) return jack_remove_properties(client, subject); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().remove_properties_ptr != nullptr) return getBridgeInstance().remove_properties_ptr(client, subject); #endif @@ -2262,7 +2215,7 @@ bool jackbridge_remove_all_properties(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_remove_all_properties(client) == 0); #else - if (! JackBridge::usingRtAudioOrSDL) + if (usingRealJACK) if (getBridgeInstance().remove_all_properties_ptr != nullptr) return (getBridgeInstance().remove_all_properties_ptr(client) == 0); #endif @@ -2275,7 +2228,7 @@ bool jackbridge_set_property_change_callback(jack_client_t* client, JackProperty #elif defined(JACKBRIDGE_DIRECT) return (jack_set_property_change_callback(client, callback, arg) == 0); #else - if (! JackBridge::usingRtAudioOrSDL && getBridgeInstance().set_property_change_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_property_change_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_prop_change(callback); diff --git a/distrho/src/jackbridge/NativeBridge.hpp b/distrho/src/jackbridge/NativeBridge.hpp new file mode 100644 index 00000000..3b1d4a79 --- /dev/null +++ b/distrho/src/jackbridge/NativeBridge.hpp @@ -0,0 +1,213 @@ +/* + * Native Bridge for DPF + * Copyright (C) 2021-2022 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef NATIVE_BRIDGE_HPP_INCLUDED +#define NATIVE_BRIDGE_HPP_INCLUDED + +#include "JackBridge.hpp" + +#include "../../extra/RingBuffer.hpp" + +using DISTRHO_NAMESPACE::HeapRingBuffer; + +struct NativeBridge { + // Current status information + uint bufferSize = 0; + uint sampleRate = 0; + + // Port caching information + uint numAudioIns = 0; + uint numAudioOuts = 0; + uint numMidiIns = 0; + uint numMidiOuts = 0; + + // JACK callbacks + JackProcessCallback jackProcessCallback = nullptr; + void* jackProcessArg = nullptr; + + // Runtime buffers + enum PortMask { + kPortMaskAudio = 0x1000, + kPortMaskMIDI = 0x2000, + kPortMaskInput = 0x4000, + kPortMaskOutput = 0x8000, + kPortMaskInputMIDI = kPortMaskInput|kPortMaskMIDI, + kPortMaskOutputMIDI = kPortMaskOutput|kPortMaskMIDI, + }; +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + float* audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS] = {}; + float* audioBufferStorage = nullptr; +#endif +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT + static constexpr const uint32_t kMaxMIDIInputMessageSize = 3; + uint8_t midiDataStorage[kMaxMIDIInputMessageSize]; + HeapRingBuffer midiInBufferCurrent; + HeapRingBuffer midiInBufferPending; +#endif +#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + HeapRingBuffer midiOutBuffer; +#endif + + virtual ~NativeBridge() {} + virtual bool open(const char* const clientName) = 0; + virtual bool close() = 0; + virtual bool activate() = 0; + virtual bool deactivate() = 0; + + uint32_t getEventCount() + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + // NOTE: this function is only called once per run + midiInBufferCurrent.copyFromAndClearOther(midiInBufferPending); + return midiInBufferCurrent.getReadableDataSize() / (kMaxMIDIInputMessageSize + 1u); + #else + return 0; + #endif + } + + bool getEvent(jack_midi_event_t* const event) + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + // NOTE: this function is called for all events in index succession + if (midiInBufferCurrent.getReadableDataSize() >= (kMaxMIDIInputMessageSize + 1u)) + { + event->time = 0; // TODO + event->size = midiInBufferCurrent.readByte(); + event->buffer = midiDataStorage; + return midiInBufferCurrent.readCustomData(midiDataStorage, kMaxMIDIInputMessageSize); + } + #endif + return false; + } + + void clearEventBuffer() + { + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + midiOutBuffer.clearData(); + #endif + } + + bool writeEvent(const jack_nframes_t time, const jack_midi_data_t* const data, const uint32_t size) + { + if (size > 3) + return false; + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if (midiOutBuffer.writeByte(size) && midiOutBuffer.writeCustomData(data, size)) + { + bool fail = false; + // align + switch (size) + { + case 1: fail |= !midiOutBuffer.writeByte(0); + // fall-through + case 2: fail |= !midiOutBuffer.writeByte(0); + } + fail |= !midiOutBuffer.writeUInt(time); + midiOutBuffer.commitWrite(); + return !fail; + } + midiOutBuffer.commitWrite(); + #endif + return false; + } + + void allocBuffers() + { + DISTRHO_SAFE_ASSERT_RETURN(bufferSize != 0,); + + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + audioBufferStorage = new float[bufferSize*(DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS)]; + + for (uint i=0; i 0 + std::memset(audioBufferStorage, 0, sizeof(float)*bufferSize*DISTRHO_PLUGIN_NUM_INPUTS); + #endif + + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + midiInBufferCurrent.createBuffer(kMaxMIDIInputMessageSize * 512); + midiInBufferPending.createBuffer(kMaxMIDIInputMessageSize * 512); + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + midiOutBuffer.createBuffer(2048); + #endif + } + + void freeBuffers() + { + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + delete[] audioBufferStorage; + audioBufferStorage = nullptr; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + midiInBufferCurrent.deleteBuffer(); + midiInBufferPending.deleteBuffer(); + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + midiOutBuffer.deleteBuffer(); + #endif + } + + jack_port_t* registerPort(const char* const type, const ulong flags) + { + bool isAudio, isInput; + + /**/ if (std::strcmp(type, JACK_DEFAULT_AUDIO_TYPE) == 0) + isAudio = true; + else if (std::strcmp(type, JACK_DEFAULT_MIDI_TYPE) == 0) + isAudio = false; + else + return nullptr; + + /**/ if (flags & JackPortIsInput) + isInput = true; + else if (flags & JackPortIsOutput) + isInput = false; + else + return nullptr; + + const uintptr_t ret = (isAudio ? kPortMaskAudio : kPortMaskMIDI) + | (isInput ? kPortMaskInput : kPortMaskOutput); + + return (jack_port_t*)(ret + (isAudio ? (isInput ? numAudioIns++ : numAudioOuts++) + : (isInput ? numMidiIns++ : numMidiOuts++))); + } + + void* getPortBuffer(jack_port_t* const port) + { + const uintptr_t portMask = (uintptr_t)port; + DISTRHO_SAFE_ASSERT_RETURN(portMask != 0x0, nullptr); + + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + if (portMask & kPortMaskAudio) + return audioBuffers[(portMask & kPortMaskInput ? 0 : DISTRHO_PLUGIN_NUM_INPUTS) + (portMask & 0x0fff)]; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + if ((portMask & kPortMaskInputMIDI) == kPortMaskInputMIDI) + return (void*)0x1; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if ((portMask & kPortMaskOutputMIDI) == kPortMaskOutputMIDI) + return (void*)0x2; + #endif + + return nullptr; + } +}; + +#endif // NATIVE_BRIDGE_HPP_INCLUDED diff --git a/distrho/src/jackbridge/RtAudioBridge.hpp b/distrho/src/jackbridge/RtAudioBridge.hpp index 6f2faa8b..146ed149 100644 --- a/distrho/src/jackbridge/RtAudioBridge.hpp +++ b/distrho/src/jackbridge/RtAudioBridge.hpp @@ -1,5 +1,5 @@ /* - * RtAudioBridge for DPF + * RtAudio Bridge for DPF * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with @@ -14,10 +14,14 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef RTAUDIOBRIDGE_HPP_INCLUDED -#define RTAUDIOBRIDGE_HPP_INCLUDED +#ifndef RTAUDIO_BRIDGE_HPP_INCLUDED +#define RTAUDIO_BRIDGE_HPP_INCLUDED -#include "JackBridge.hpp" +#include "NativeBridge.hpp" + +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS == 0 +# error RtAudio without audio does not make sense +#endif #if defined(DISTRHO_OS_MAC) # define __MACOSX_CORE__ @@ -37,50 +41,20 @@ # define Point CorePoint /* fix conflict between DGL and macOS Point name */ # include "rtaudio/RtAudio.h" # undef Point -# include "../../extra/RingBuffer.hpp" # include "../../extra/ScopedPointer.hpp" -using DISTRHO_NAMESPACE::HeapRingBuffer; using DISTRHO_NAMESPACE::ScopedPointer; -struct RtAudioBridge { +struct RtAudioBridge : NativeBridge { // pointer to RtAudio instance ScopedPointer handle; - // RtAudio information - uint bufferSize = 0; - uint sampleRate = 0; - - // Port caching information - uint numAudioIns = 0; - uint numAudioOuts = 0; - uint numMidiIns = 0; - uint numMidiOuts = 0; - - // JACK callbacks - JackProcessCallback jackProcessCallback = nullptr; - void* jackProcessArg = nullptr; - - // Runtime buffers - enum PortMask { - kPortMaskAudio = 0x1000, - kPortMaskMIDI = 0x2000, - kPortMaskInput = 0x4000, - kPortMaskOutput = 0x8000, - kPortMaskInputMIDI = kPortMaskInput|kPortMaskMIDI, - kPortMaskOutputMIDI = kPortMaskOutput|kPortMaskMIDI, - }; -#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - float* audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS]; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - HeapRingBuffer midiInBuffer; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - HeapRingBuffer midiOutBuffer; -#endif + const char* getVersion() const noexcept + { + return RTAUDIO_VERSION; + } - bool open() + bool open(const char* const clientName) override { ScopedPointer rtAudio; @@ -90,24 +64,31 @@ struct RtAudioBridge { uint rtAudioBufferFrames = 512; -#if DISTRHO_PLUGIN_NUM_INPUTS > 0 + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 RtAudio::StreamParameters inParams; - RtAudio::StreamParameters* const inParamsPtr = &inParams; inParams.deviceId = rtAudio->getDefaultInputDevice(); inParams.nChannels = DISTRHO_PLUGIN_NUM_INPUTS; -#else + RtAudio::StreamParameters* const inParamsPtr = &inParams; + #else RtAudio::StreamParameters* const inParamsPtr = nullptr; -#endif + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 RtAudio::StreamParameters outParams; outParams.deviceId = rtAudio->getDefaultOutputDevice(); outParams.nChannels = DISTRHO_PLUGIN_NUM_OUTPUTS; + RtAudio::StreamParameters* const outParamsPtr = &outParams; + #else + RtAudio::StreamParameters* const outParamsPtr = nullptr; + #endif RtAudio::StreamOptions opts; opts.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_ALSA_USE_DEFAULT; + opts.streamName = clientName; try { - rtAudio->openStream(&outParams, inParamsPtr, RTAUDIO_FLOAT32, 48000, &rtAudioBufferFrames, RtAudioCallback, this, &opts, nullptr); + rtAudio->openStream(outParamsPtr, inParamsPtr, RTAUDIO_FLOAT32, 48000, &rtAudioBufferFrames, + RtAudioCallback, this, &opts, nullptr); } catch (const RtAudioError& err) { d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__); return false; @@ -116,17 +97,10 @@ struct RtAudioBridge { handle = rtAudio; bufferSize = rtAudioBufferFrames; sampleRate = handle->getStreamSampleRate(); - -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - midiInBuffer.createBuffer(128); -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - midiOutBuffer.createBuffer(128); -#endif return true; } - bool close() + bool close() override { DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false); @@ -141,82 +115,40 @@ struct RtAudioBridge { return true; } - bool activate() + bool activate() override { DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false); try { handle->startStream(); - } DISTRHO_SAFE_EXCEPTION("handle->startStream()"); + } DISTRHO_SAFE_EXCEPTION_RETURN("handle->startStream()", false); return true; } - bool deactivate() + bool deactivate() override { DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false); try { handle->stopStream(); - } DISTRHO_SAFE_EXCEPTION("handle->stopStream()"); + } DISTRHO_SAFE_EXCEPTION_RETURN("handle->stopStream()", false); return true; } - jack_port_t* registerPort(const char* const type, const ulong flags) - { - bool isAudio, isInput; - - /**/ if (std::strcmp(type, JACK_DEFAULT_AUDIO_TYPE) == 0) - isAudio = true; - else if (std::strcmp(type, JACK_DEFAULT_MIDI_TYPE) == 0) - isAudio = false; - else - return nullptr; - - /**/ if (flags & JackPortIsInput) - isInput = true; - else if (flags & JackPortIsOutput) - isInput = false; - else - return nullptr; - - const uintptr_t ret = (isAudio ? kPortMaskAudio : kPortMaskMIDI) - | (isInput ? kPortMaskInput : kPortMaskOutput); - - return (jack_port_t*)(ret + (isAudio ? (isInput ? numAudioIns++ : numAudioOuts++) - : (isInput ? numMidiIns++ : numMidiOuts++))); - } - - void* getPortBuffer(jack_port_t* const port) - { - const uintptr_t portMask = (uintptr_t)port; - DISTRHO_SAFE_ASSERT_RETURN(portMask != 0x0, nullptr); - -#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - if (portMask & kPortMaskAudio) - return audioBuffers[(portMask & kPortMaskInput ? 0 : DISTRHO_PLUGIN_NUM_INPUTS) + (portMask & 0x0fff)]; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - if ((portMask & kPortMaskInputMIDI) == kPortMaskInputMIDI) - return &midiInBuffer; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - if ((portMask & kPortMaskOutputMIDI) == kPortMaskOutputMIDI) - return &midiOutBuffer; -#endif - - return nullptr; - } - static int RtAudioCallback(void* const outputBuffer, + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 void* const inputBuffer, + #else + void*, + #endif const uint numFrames, const double /* streamTime */, const RtAudioStreamStatus /* status */, void* const userData) { - RtAudioBridge* const self = (RtAudioBridge*)userData; + RtAudioBridge* const self = static_cast(userData); if (self->jackProcessCallback == nullptr) { @@ -225,35 +157,27 @@ struct RtAudioBridge { return 0; } -#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - float** const selfAudioBuffers = self->audioBuffers; - - uint i = 0; -# if DISTRHO_PLUGIN_NUM_INPUTS > 0 - if (float* const insPtr = (float*)inputBuffer) + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + if (float* const insPtr = static_cast(inputBuffer)) { - for (uint j=0; jaudioBuffers[i] = insPtr + (i * numFrames); } -# endif -# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - if (float* const outsPtr = (float*)outputBuffer) + #endif + + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + if (float* const outsPtr = static_cast(outputBuffer)) { - for (uint j=0; jaudioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i] = outsPtr + (i * numFrames); } -# endif -#endif + #endif self->jackProcessCallback(numFrames, self->jackProcessArg); - return 0; -#if DISTRHO_PLUGIN_NUM_INPUTS == 0 - // unused - (void)inputBuffer; -#endif + return 0; } }; #endif // RTAUDIO_API_TYPE -#endif // RTAUDIOBRIDGE_HPP_INCLUDED +#endif // RTAUDIO_BRIDGE_HPP_INCLUDED diff --git a/distrho/src/jackbridge/SDLBridge.hpp b/distrho/src/jackbridge/SDL2Bridge.hpp similarity index 62% rename from distrho/src/jackbridge/SDLBridge.hpp rename to distrho/src/jackbridge/SDL2Bridge.hpp index 76cf4960..84bcf5d5 100644 --- a/distrho/src/jackbridge/SDLBridge.hpp +++ b/distrho/src/jackbridge/SDL2Bridge.hpp @@ -1,5 +1,5 @@ /* - * SDLBridge for DPF + * SDL Bridge for DPF * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with @@ -14,15 +14,18 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef SDLBRIDGE_HPP_INCLUDED -#define SDLBRIDGE_HPP_INCLUDED +#ifndef SDL_BRIDGE_HPP_INCLUDED +#define SDL_BRIDGE_HPP_INCLUDED -#include "JackBridge.hpp" -#include "../../extra/RingBuffer.hpp" +#include "NativeBridge.hpp" #include -struct SDLBridge { +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS == 0 +# error SDL without audio does not make sense +#endif + +struct SDL2Bridge : NativeBridge { #if DISTRHO_PLUGIN_NUM_INPUTS > 0 SDL_AudioDeviceID captureDeviceId = 0; #endif @@ -30,43 +33,8 @@ struct SDLBridge { SDL_AudioDeviceID playbackDeviceId = 0; #endif - // SDL information - uint bufferSize = 0; - uint sampleRate = 0; - - // Port caching information - uint numAudioIns = 0; - uint numAudioOuts = 0; - uint numMidiIns = 0; - uint numMidiOuts = 0; - - // JACK callbacks - JackProcessCallback jackProcessCallback = nullptr; - void* jackProcessArg = nullptr; - - // Runtime buffers - enum PortMask { - kPortMaskAudio = 0x1000, - kPortMaskMIDI = 0x2000, - kPortMaskInput = 0x4000, - kPortMaskOutput = 0x8000, - kPortMaskInputMIDI = kPortMaskInput|kPortMaskMIDI, - kPortMaskOutputMIDI = kPortMaskOutput|kPortMaskMIDI, - }; -#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - float* audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS]; - float* audioBufferStorage; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - HeapRingBuffer midiInBuffer; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - HeapRingBuffer midiOutBuffer; -#endif - - bool open(const char* const clientName) + bool open(const char* const clientName) override { - #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 SDL_InitSubSystem(SDL_INIT_AUDIO); SDL_AudioSpec requested; @@ -78,7 +46,6 @@ struct SDLBridge { SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, clientName); // SDL_SetHint(SDL_HINT_AUDIO_RESAMPLING_MODE, "1"); - #endif #if DISTRHO_PLUGIN_NUM_INPUTS > 0 SDL_SetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME, "Capure"); @@ -144,130 +111,67 @@ struct SDLBridge { d_stderr2("Mismatch sample rate %u vs %u", receivedCapture.freq, receivedCapture.freq); return false; } + #endif + + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 bufferSize = receivedCapture.samples; sampleRate = receivedCapture.freq; - #elif DISTRHO_PLUGIN_NUM_INPUTS > 0 - bufferSize = receivedCapture.samples; - sampleRate = receivedCapture.freq; - #elif DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + #else bufferSize = receivedPlayback.samples; sampleRate = receivedPlayback.freq; - #else - d_stderr2("SDL without audio, unsupported for now"); - return false; #endif - -#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - audioBufferStorage = new float[bufferSize*(DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS)]; -#if DISTRHO_PLUGIN_NUM_INPUTS > 0 - std::memset(audioBufferStorage, 0, sizeof(float)*bufferSize*DISTRHO_PLUGIN_NUM_INPUTS); -#endif - - for (uint i=0; i 0 + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 DISTRHO_SAFE_ASSERT_RETURN(captureDeviceId != 0, false); SDL_CloseAudioDevice(captureDeviceId); captureDeviceId = 0; -#endif -#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false); SDL_CloseAudioDevice(playbackDeviceId); playbackDeviceId = 0; -#endif - -#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - delete[] audioBufferStorage; - audioBufferStorage = nullptr; -#endif + #endif + freeBuffers(); return true; } - bool activate() + bool activate() override { -#if DISTRHO_PLUGIN_NUM_INPUTS > 0 + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 DISTRHO_SAFE_ASSERT_RETURN(captureDeviceId != 0, false); SDL_PauseAudioDevice(captureDeviceId, 0); -#endif -#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false); SDL_PauseAudioDevice(playbackDeviceId, 0); -#endif + #endif return true; } - bool deactivate() + bool deactivate() override { -#if DISTRHO_PLUGIN_NUM_INPUTS > 0 + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 DISTRHO_SAFE_ASSERT_RETURN(captureDeviceId != 0, false); SDL_PauseAudioDevice(captureDeviceId, 1); -#endif -#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false); SDL_PauseAudioDevice(playbackDeviceId, 1); -#endif + #endif return true; } - jack_port_t* registerPort(const char* const type, const ulong flags) - { - bool isAudio, isInput; - - /**/ if (std::strcmp(type, JACK_DEFAULT_AUDIO_TYPE) == 0) - isAudio = true; - else if (std::strcmp(type, JACK_DEFAULT_MIDI_TYPE) == 0) - isAudio = false; - else - return nullptr; - - /**/ if (flags & JackPortIsInput) - isInput = true; - else if (flags & JackPortIsOutput) - isInput = false; - else - return nullptr; - - const uintptr_t ret = (isAudio ? kPortMaskAudio : kPortMaskMIDI) - | (isInput ? kPortMaskInput : kPortMaskOutput); - - return (jack_port_t*)(ret + (isAudio ? (isInput ? numAudioIns++ : numAudioOuts++) - : (isInput ? numMidiIns++ : numMidiOuts++))); - } - - void* getPortBuffer(jack_port_t* const port) - { - const uintptr_t portMask = (uintptr_t)port; - DISTRHO_SAFE_ASSERT_RETURN(portMask != 0x0, nullptr); - -#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - if (portMask & kPortMaskAudio) - return audioBuffers[(portMask & kPortMaskInput ? 0 : DISTRHO_PLUGIN_NUM_INPUTS) + (portMask & 0x0fff)]; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - if ((portMask & kPortMaskInputMIDI) == kPortMaskInputMIDI) - return &midiInBuffer; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - if ((portMask & kPortMaskOutputMIDI) == kPortMaskOutputMIDI) - return &midiOutBuffer; -#endif - - return nullptr; - } - -#if DISTRHO_PLUGIN_NUM_INPUTS > 0 + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 static void AudioInputCallback(void* const userData, uchar* const stream, const int len) { - SDLBridge* const self = (SDLBridge*)userData; + NativeBridge* const self = static_cast(userData); // safety checks DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr,); @@ -287,14 +191,17 @@ struct SDLBridge { self->audioBuffers[i][j] = fstream[j * DISTRHO_PLUGIN_NUM_INPUTS + i]; } + #if DISTRHO_PLUGIN_NUM_OUTPUTS == 0 + // if there are no outputs, run process callback now self->jackProcessCallback(numFrames, self->jackProcessArg); + #endif } -#endif + #endif -#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 static void AudioOutputCallback(void* const userData, uchar* const stream, const int len) { - SDLBridge* const self = (SDLBridge*)userData; + NativeBridge* const self = static_cast(userData); // safety checks DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr,); @@ -309,10 +216,7 @@ struct SDLBridge { const uint numFrames = static_cast(len / sizeof(float) / DISTRHO_PLUGIN_NUM_OUTPUTS); DISTRHO_SAFE_ASSERT_UINT2_RETURN(numFrames == self->bufferSize, numFrames, self->bufferSize,); - #if DISTRHO_PLUGIN_NUM_INPUTS == 0 - // if there are no inputs, run process callback now self->jackProcessCallback(numFrames, self->jackProcessArg); - #endif float* const fstream = (float*)stream; @@ -322,7 +226,7 @@ struct SDLBridge { fstream[j * DISTRHO_PLUGIN_NUM_OUTPUTS + i] = self->audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i][j]; } } -#endif + #endif }; -#endif +#endif // SDL_BRIDGE_HPP_INCLUDED diff --git a/distrho/src/jackbridge/WebBridge.hpp b/distrho/src/jackbridge/WebBridge.hpp new file mode 100644 index 00000000..1b97760d --- /dev/null +++ b/distrho/src/jackbridge/WebBridge.hpp @@ -0,0 +1,354 @@ +/* + * Web Audio + MIDI Bridge for DPF + * Copyright (C) 2021-2022 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WEB_BRIDGE_HPP_INCLUDED +#define WEB_BRIDGE_HPP_INCLUDED + +#include "NativeBridge.hpp" + +#include + +struct WebBridge : NativeBridge { +#if DISTRHO_PLUGIN_NUM_INPUTS > 0 + bool captureAvailable = false; +#endif +#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + bool playbackAvailable = false; +#endif +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + bool midiAvailable = false; +#endif + bool active = false; + double timestamp = 0; + + WebBridge() + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + captureAvailable = EM_ASM_INT({ + if (typeof(navigator.mediaDevices) !== 'undefined' && typeof(navigator.mediaDevices.getUserMedia) !== 'undefined') + return 1; + if (typeof(navigator.webkitGetUserMedia) !== 'undefined') + return 1; + return false; + }) != 0; + #endif + + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + playbackAvailable = EM_ASM_INT({ + if (typeof(AudioContext) !== 'undefined') + return 1; + if (typeof(webkitAudioContext) !== 'undefined') + return 1; + return 0; + }) != 0; + #endif + + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + midiAvailable = EM_ASM_INT({ + return typeof(navigator.requestMIDIAccess) === 'function' ? 1 : 0; + }) != 0; + #endif + } + + bool open(const char*) override + { + // early bail out if required features are not supported + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + if (!captureAvailable) + { + #if DISTRHO_PLUGIN_NUM_OUTPUTS == 0 + d_stderr2("Audio capture is not supported"); + return false; + #else + if (!playbackAvailable) + { + d_stderr2("Audio capture and playback are not supported"); + return false; + } + d_stderr2("Audio capture is not supported, but can still use playback"); + #endif + } + #endif + + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + if (!playbackAvailable) + { + d_stderr2("Audio playback is not supported"); + return false; + } + #endif + + const bool initialized = EM_ASM_INT({ + if (typeof(Module['WebAudioBridge']) === 'undefined') { + Module['WebAudioBridge'] = {}; + } + + var WAB = Module['WebAudioBridge']; + if (!WAB.audioContext) { + if (typeof(AudioContext) !== 'undefined') { + WAB.audioContext = new AudioContext(); + } else if (typeof(webkitAudioContext) !== 'undefined') { + WAB.audioContext = new webkitAudioContext(); + } + } + + return WAB.audioContext === undefined ? 0 : 1; + }) != 0; + + if (!initialized) + { + d_stderr2("Failed to initialize web audio"); + return false; + } + + bufferSize = 512; + sampleRate = EM_ASM_INT_V({ + var WAB = Module['WebAudioBridge']; + return WAB.audioContext.sampleRate; + }); + + allocBuffers(); + + EM_ASM({ + var numInputs = $0; + var numOutputs = $1; + var bufferSize = $2; + var WAB = Module['WebAudioBridge']; + + // main processor + WAB.processor = WAB.audioContext['createScriptProcessor'](bufferSize, numInputs, numOutputs); + WAB.processor['onaudioprocess'] = function (e) { + var timestamp = performance.now(); + for (var i = 0; i < numInputs; ++i) { + var buffer = e['inputBuffer']['getChannelData'](i); + for (var j = 0; j < bufferSize; ++j) { + // setValue($3 + ((bufferSize * i) + j) * 4, buffer[j], 'float'); + HEAPF32[$3 + (((bufferSize * i) + j) << 2) >> 2] = buffer[j]; + } + } + dynCall('vif', $4, [$5, timestamp]); + for (var i = 0; i < numOutputs; ++i) { + var buffer = e['outputBuffer']['getChannelData'](i); + var offset = bufferSize * (numInputs + i); + for (var j = 0; j < bufferSize; ++j) { + buffer[j] = HEAPF32[$3 + ((offset + j) << 2) >> 2]; + } + } + }; + + // connect to output + WAB.processor['connect'](WAB.audioContext['destination']); + + // resume/start playback on first click + document.addEventListener('click', function(e) { + var WAB = Module['WebAudioBridge']; + console.log(WAB.audioContext.state); + if (WAB.audioContext.state === 'suspended') + WAB.audioContext.resume(); + }); + }, DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS, bufferSize, audioBufferStorage, WebAudioCallback, this); + +// enableInput(); + enableMIDI(); + + return true; + } + + bool close() override + { + freeBuffers(); + return true; + } + + bool activate() override + { + active = true; + return true; + } + + bool deactivate() override + { + active = false; + return true; + } + + bool enableInput() + { + DISTRHO_SAFE_ASSERT_RETURN(DISTRHO_PLUGIN_NUM_INPUTS > 0, false); + + EM_ASM({ + var numInputs = $0; + var WAB = Module['WebAudioBridge']; + + var constraints = {}; + // we need to use this weird awkward way for objects, otherwise build fails + constraints['audio'] = true; + constraints['video'] = false; + constraints['latency'] = 0; + constraints['sampleSize'] = 24; + constraints['mandatory'] = {}; + constraints['mandatory']['autoGainControl'] = false; + constraints['mandatory']['echoCancellation'] = false; + constraints['mandatory']['noiseSuppression'] = false; + constraints['mandatory']['channelCount'] = numInputs; + // old property for chrome + constraints['mandatory']['googAutoGainControl'] = false; + + var success = function(stream) { + WAB.captureStreamNode = WAB.audioContext['createMediaStreamSource'](stream); + WAB.captureStreamNode.connect(WAB.processor); + }; + var fail = function() { + }; + + if (navigator.mediaDevices !== undefined && navigator.mediaDevices.getUserMedia !== undefined) { + navigator.mediaDevices.getUserMedia(constraints).then(success).catch(fail); + } else if (navigator.webkitGetUserMedia !== undefined) { + navigator.webkitGetUserMedia(constraints, success, fail); + } + }, DISTRHO_PLUGIN_NUM_INPUTS); + + return true; + } + + bool enableMIDI() + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if (midiAvailable) + { + EM_ASM({ + var useInput = !!$0; + var useOutput = !!$1; + var maxSize = $2; + var WAB = Module['WebAudioBridge']; + + var offset = Module._malloc(maxSize); + + var inputCallback = function(event) { + if (event.data.length > maxSize) + return; + var buffer = new Uint8Array(Module.HEAPU8.buffer, offset, maxSize); + buffer.set(event.data); + dynCall('viiif', $3, [$4, buffer.byteOffset, event.data.length, event.timeStamp]); + }; + var stateCallback = function(event) { + if (event.port.state === 'connected' && event.port.connection === 'open') { + if (useInput && event.port.type === 'input') { + if (event.port.name.indexOf('Midi Through') < 0) + event.port.onmidimessage = inputCallback; + } else if (useOutput && event.port.type === 'output') { + event.port.open(); + } + } + }; + + var success = function(midi) { + WAB.midi = midi; + midi.onstatechange = stateCallback; + if (useInput) { + midi.inputs.forEach(function(port) { + if (port.name.indexOf('Midi Through') < 0) + port.onmidimessage = inputCallback; + }); + } + if (useOutput) { + midi.outputs.forEach(function(port) { + port.open(); + }); + } + }; + var fail = function(why) { + console.log("midi access failed:", why); + }; + + navigator.requestMIDIAccess().then(success, fail); + }, DISTRHO_PLUGIN_WANT_MIDI_INPUT, DISTRHO_PLUGIN_WANT_MIDI_OUTPUT, kMaxMIDIInputMessageSize, WebMIDICallback, this); + + return true; + } + else + #endif + { + d_stderr2("MIDI is not supported"); + return false; + } + } + + static void WebAudioCallback(void* const userData, const double timestamp) + { + WebBridge* const self = static_cast(userData); + self->timestamp = timestamp; + + const uint numFrames = self->bufferSize; + + if (self->jackProcessCallback != nullptr && self->active) + { + self->jackProcessCallback(numFrames, self->jackProcessArg); + + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if (self->midiAvailable) + { + static_assert(kMaxMIDIInputMessageSize + 1u == 4, "change code if bumping this value"); + uint32_t offset = 0; + uint8_t bytes[4] = {}; + + while (self->midiOutBuffer.isDataAvailableForReading() && + self->midiOutBuffer.readCustomData(bytes, ARRAY_SIZE(bytes))) + { + offset = self->midiOutBuffer.readUInt(); + + EM_ASM({ + var WAB = Module['WebAudioBridge']; + if (WAB.midi) { + var timestamp = performance.now() + $0; + var size = $1; + WAB.midi.outputs.forEach(function(port) { + if (port.state !== 'disconnected') { + port.send(size == 3 ? [ $2, $3, $4 ] : + size == 2 ? [ $2, $3 ] : + [ $2 ], timestamp); + } + }); + } + }, offset, bytes[0], bytes[1], bytes[2], bytes[3]); + } + self->midiOutBuffer.clearData(); + } + #endif + } + else + { + for (uint i=0; iaudioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i], 0, sizeof(float)*numFrames); + } + } + + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + static void WebMIDICallback(void* const userData, uint8_t* const data, const int len, const double timestamp) + { + DISTRHO_SAFE_ASSERT_RETURN(len > 0 && len <= (int)kMaxMIDIInputMessageSize,); + + WebBridge* const self = static_cast(userData); + + // TODO timestamp handling + self->midiInBufferPending.writeByte(static_cast(len)); + self->midiInBufferPending.writeCustomData(data, kMaxMIDIInputMessageSize); + self->midiInBufferPending.commitWrite(); + } + #endif +}; + +#endif // WEB_BRIDGE_HPP_INCLUDED