commit ec02b889233b1145db74fda7fe1565d645f42d02
parent f1e157a03c40637c9055ddf82e7b0543b386c48a
Author: falkTX <falktx@falktx.com>
Date: Mon, 11 Jul 2022 04:22:13 +0100
Rework native audio standalone fallback code, add full wasm stuff
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
9 files changed, 1078 insertions(+), 687 deletions(-)
diff --git 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,12 +334,15 @@ 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
# backwards compat, always available/enabled
@@ -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
@@ -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
@@ -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
@@ -35,16 +35,24 @@
#include <cerrno>
#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<jack_options_t>(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<jack_options_t>(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<ulong>(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<uint32_t>(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<uint32_t>(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<jack_latency_callback_mode_t>(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<jack_latency_callback_mode_t>(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<jack_latency_callback_mode_t>(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<jack_latency_callback_mode_t>(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<ulong>(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
@@ -0,0 +1,213 @@
+/*
+ * Native Bridge for DPF
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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<DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
+ audioBuffers[i] = audioBufferStorage + (bufferSize * i);
+ #endif
+
+ #if DISTRHO_PLUGIN_NUM_INPUTS > 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
@@ -1,5 +1,5 @@
/*
- * RtAudioBridge for DPF
+ * RtAudio Bridge for DPF
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
*
* 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<RtAudio> 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> 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<RtAudioBridge*>(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<float*>(inputBuffer))
{
- for (uint j=0; j<DISTRHO_PLUGIN_NUM_INPUTS; ++j, ++i)
- selfAudioBuffers[i] = insPtr + (j * numFrames);
+ for (uint i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
+ self->audioBuffers[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<float*>(outputBuffer))
{
- for (uint j=0; j<DISTRHO_PLUGIN_NUM_OUTPUTS; ++j, ++i)
- selfAudioBuffers[i] = outsPtr + (j * numFrames);
+ for (uint i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
+ self->audioBuffers[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/SDL2Bridge.hpp b/distrho/src/jackbridge/SDL2Bridge.hpp
@@ -0,0 +1,232 @@
+/*
+ * SDL Bridge for DPF
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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 SDL_BRIDGE_HPP_INCLUDED
+#define SDL_BRIDGE_HPP_INCLUDED
+
+#include "NativeBridge.hpp"
+
+#include <SDL.h>
+
+#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
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ SDL_AudioDeviceID playbackDeviceId = 0;
+#endif
+
+ bool open(const char* const clientName) override
+ {
+ SDL_InitSubSystem(SDL_INIT_AUDIO);
+
+ SDL_AudioSpec requested;
+ std::memset(&requested, 0, sizeof(requested));
+ requested.format = AUDIO_F32SYS;
+ requested.freq = 48000;
+ requested.samples = 512;
+ requested.userdata = this;
+
+ SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, clientName);
+ // SDL_SetHint(SDL_HINT_AUDIO_RESAMPLING_MODE, "1");
+
+ #if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ SDL_SetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME, "Capure");
+ requested.channels = DISTRHO_PLUGIN_NUM_INPUTS;
+ requested.callback = AudioInputCallback;
+
+ SDL_AudioSpec receivedCapture;
+ captureDeviceId = SDL_OpenAudioDevice(nullptr, 1, &requested, &receivedCapture,
+ SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE);
+ if (captureDeviceId == 0)
+ {
+ d_stderr2("Failed to open SDL playback device, error was: %s", SDL_GetError());
+ return false;
+ }
+
+ if (receivedCapture.channels != DISTRHO_PLUGIN_NUM_INPUTS)
+ {
+ SDL_CloseAudioDevice(captureDeviceId);
+ captureDeviceId = 0;
+ d_stderr2("Invalid or missing audio input channels");
+ return false;
+ }
+ #endif
+
+ #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ SDL_AudioSpec receivedPlayback;
+ SDL_SetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME, "Playback");
+ requested.channels = DISTRHO_PLUGIN_NUM_OUTPUTS;
+ requested.callback = AudioOutputCallback;
+
+ playbackDeviceId = SDL_OpenAudioDevice(nullptr, 0, &requested, &receivedPlayback,
+ SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE);
+ if (playbackDeviceId == 0)
+ {
+ d_stderr2("Failed to open SDL playback device, error was: %s", SDL_GetError());
+ return false;
+ }
+
+ if (receivedPlayback.channels != DISTRHO_PLUGIN_NUM_OUTPUTS)
+ {
+ SDL_CloseAudioDevice(playbackDeviceId);
+ playbackDeviceId = 0;
+ d_stderr2("Invalid or missing audio output channels");
+ return false;
+ }
+ #endif
+
+ #if DISTRHO_PLUGIN_NUM_INPUTS > 0 && DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ // if using both input and output, make sure they match
+ if (receivedCapture.samples != receivedPlayback.samples)
+ {
+ SDL_CloseAudioDevice(captureDeviceId);
+ SDL_CloseAudioDevice(playbackDeviceId);
+ captureDeviceId = playbackDeviceId = 0;
+ d_stderr2("Mismatch buffer size %u vs %u", receivedCapture.samples, receivedCapture.samples);
+ return false;
+ }
+ if (receivedCapture.freq != receivedPlayback.freq)
+ {
+ SDL_CloseAudioDevice(captureDeviceId);
+ SDL_CloseAudioDevice(playbackDeviceId);
+ captureDeviceId = playbackDeviceId = 0;
+ 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;
+ #else
+ bufferSize = receivedPlayback.samples;
+ sampleRate = receivedPlayback.freq;
+ #endif
+
+ allocBuffers();
+ return true;
+ }
+
+ bool close() override
+ {
+ #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
+ DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false);
+ SDL_CloseAudioDevice(playbackDeviceId);
+ playbackDeviceId = 0;
+ #endif
+
+ freeBuffers();
+ return true;
+ }
+
+ bool activate() override
+ {
+ #if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ DISTRHO_SAFE_ASSERT_RETURN(captureDeviceId != 0, false);
+ SDL_PauseAudioDevice(captureDeviceId, 0);
+ #endif
+ #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false);
+ SDL_PauseAudioDevice(playbackDeviceId, 0);
+ #endif
+ return true;
+ }
+
+ bool deactivate() override
+ {
+ #if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ DISTRHO_SAFE_ASSERT_RETURN(captureDeviceId != 0, false);
+ SDL_PauseAudioDevice(captureDeviceId, 1);
+ #endif
+ #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false);
+ SDL_PauseAudioDevice(playbackDeviceId, 1);
+ #endif
+ return true;
+ }
+
+ #if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ static void AudioInputCallback(void* const userData, uchar* const stream, const int len)
+ {
+ NativeBridge* const self = static_cast<NativeBridge*>(userData);
+
+ // safety checks
+ DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr,);
+ DISTRHO_SAFE_ASSERT_RETURN(len > 0,);
+
+ if (self->jackProcessCallback == nullptr)
+ return;
+
+ const uint numFrames = static_cast<uint>(len / sizeof(float) / DISTRHO_PLUGIN_NUM_INPUTS);
+ DISTRHO_SAFE_ASSERT_UINT2_RETURN(numFrames == self->bufferSize, numFrames, self->bufferSize,);
+
+ const float* const fstream = (const float*)stream;
+
+ for (uint i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
+ {
+ for (uint j=0; j<numFrames; ++j)
+ 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
+
+ #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ static void AudioOutputCallback(void* const userData, uchar* const stream, const int len)
+ {
+ NativeBridge* const self = static_cast<NativeBridge*>(userData);
+
+ // safety checks
+ DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr,);
+ DISTRHO_SAFE_ASSERT_RETURN(len > 0,);
+
+ if (self->jackProcessCallback == nullptr)
+ {
+ std::memset(stream, 0, len);
+ return;
+ }
+
+ const uint numFrames = static_cast<uint>(len / sizeof(float) / DISTRHO_PLUGIN_NUM_OUTPUTS);
+ DISTRHO_SAFE_ASSERT_UINT2_RETURN(numFrames == self->bufferSize, numFrames, self->bufferSize,);
+
+ self->jackProcessCallback(numFrames, self->jackProcessArg);
+
+ float* const fstream = (float*)stream;
+
+ for (uint i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
+ {
+ for (uint j=0; j < numFrames; ++j)
+ fstream[j * DISTRHO_PLUGIN_NUM_OUTPUTS + i] = self->audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i][j];
+ }
+ }
+ #endif
+};
+
+#endif // SDL_BRIDGE_HPP_INCLUDED
diff --git a/distrho/src/jackbridge/SDLBridge.hpp b/distrho/src/jackbridge/SDLBridge.hpp
@@ -1,328 +0,0 @@
-/*
- * SDLBridge for DPF
- * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
- *
- * 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 SDLBRIDGE_HPP_INCLUDED
-#define SDLBRIDGE_HPP_INCLUDED
-
-#include "JackBridge.hpp"
-#include "../../extra/RingBuffer.hpp"
-
-#include <SDL.h>
-
-struct SDLBridge {
-#if DISTRHO_PLUGIN_NUM_INPUTS > 0
- SDL_AudioDeviceID captureDeviceId = 0;
-#endif
-#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- 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)
- {
- #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- SDL_InitSubSystem(SDL_INIT_AUDIO);
-
- SDL_AudioSpec requested;
- std::memset(&requested, 0, sizeof(requested));
- requested.format = AUDIO_F32SYS;
- requested.freq = 48000;
- requested.samples = 512;
- requested.userdata = this;
-
- 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");
- requested.channels = DISTRHO_PLUGIN_NUM_INPUTS;
- requested.callback = AudioInputCallback;
-
- SDL_AudioSpec receivedCapture;
- captureDeviceId = SDL_OpenAudioDevice(nullptr, 1, &requested, &receivedCapture,
- SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE);
- if (captureDeviceId == 0)
- {
- d_stderr2("Failed to open SDL playback device, error was: %s", SDL_GetError());
- return false;
- }
-
- if (receivedCapture.channels != DISTRHO_PLUGIN_NUM_INPUTS)
- {
- SDL_CloseAudioDevice(captureDeviceId);
- captureDeviceId = 0;
- d_stderr2("Invalid or missing audio input channels");
- return false;
- }
- #endif
-
- #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- SDL_AudioSpec receivedPlayback;
- SDL_SetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME, "Playback");
- requested.channels = DISTRHO_PLUGIN_NUM_OUTPUTS;
- requested.callback = AudioOutputCallback;
-
- playbackDeviceId = SDL_OpenAudioDevice(nullptr, 0, &requested, &receivedPlayback,
- SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE);
- if (playbackDeviceId == 0)
- {
- d_stderr2("Failed to open SDL playback device, error was: %s", SDL_GetError());
- return false;
- }
-
- if (receivedPlayback.channels != DISTRHO_PLUGIN_NUM_OUTPUTS)
- {
- SDL_CloseAudioDevice(playbackDeviceId);
- playbackDeviceId = 0;
- d_stderr2("Invalid or missing audio output channels");
- return false;
- }
- #endif
-
- #if DISTRHO_PLUGIN_NUM_INPUTS > 0 && DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- // if using both input and output, make sure they match
- if (receivedCapture.samples != receivedPlayback.samples)
- {
- SDL_CloseAudioDevice(captureDeviceId);
- SDL_CloseAudioDevice(playbackDeviceId);
- captureDeviceId = playbackDeviceId = 0;
- d_stderr2("Mismatch buffer size %u vs %u", receivedCapture.samples, receivedCapture.samples);
- return false;
- }
- if (receivedCapture.freq != receivedPlayback.freq)
- {
- SDL_CloseAudioDevice(captureDeviceId);
- SDL_CloseAudioDevice(playbackDeviceId);
- captureDeviceId = playbackDeviceId = 0;
- d_stderr2("Mismatch sample rate %u vs %u", receivedCapture.freq, receivedCapture.freq);
- return false;
- }
- bufferSize = receivedCapture.samples;
- sampleRate = receivedCapture.freq;
- #elif DISTRHO_PLUGIN_NUM_INPUTS > 0
- bufferSize = receivedCapture.samples;
- sampleRate = receivedCapture.freq;
- #elif DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- 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<DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
- audioBuffers[i] = audioBufferStorage + (bufferSize * i);
-#endif
-
- return true;
- }
-
- bool close()
- {
-#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
- 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
-
- return true;
- }
-
- bool activate()
- {
-#if DISTRHO_PLUGIN_NUM_INPUTS > 0
- DISTRHO_SAFE_ASSERT_RETURN(captureDeviceId != 0, false);
- SDL_PauseAudioDevice(captureDeviceId, 0);
-#endif
-#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false);
- SDL_PauseAudioDevice(playbackDeviceId, 0);
-#endif
- return true;
- }
-
- bool deactivate()
- {
-#if DISTRHO_PLUGIN_NUM_INPUTS > 0
- DISTRHO_SAFE_ASSERT_RETURN(captureDeviceId != 0, false);
- SDL_PauseAudioDevice(captureDeviceId, 1);
-#endif
-#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false);
- SDL_PauseAudioDevice(playbackDeviceId, 1);
-#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
- static void AudioInputCallback(void* const userData, uchar* const stream, const int len)
- {
- SDLBridge* const self = (SDLBridge*)userData;
-
- // safety checks
- DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr,);
- DISTRHO_SAFE_ASSERT_RETURN(len > 0,);
-
- if (self->jackProcessCallback == nullptr)
- return;
-
- const uint numFrames = static_cast<uint>(len / sizeof(float) / DISTRHO_PLUGIN_NUM_INPUTS);
- DISTRHO_SAFE_ASSERT_UINT2_RETURN(numFrames == self->bufferSize, numFrames, self->bufferSize,);
-
- const float* const fstream = (const float*)stream;
-
- for (uint i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
- {
- for (uint j=0; j<numFrames; ++j)
- self->audioBuffers[i][j] = fstream[j * DISTRHO_PLUGIN_NUM_INPUTS + i];
- }
-
- self->jackProcessCallback(numFrames, self->jackProcessArg);
- }
-#endif
-
-#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- static void AudioOutputCallback(void* const userData, uchar* const stream, const int len)
- {
- SDLBridge* const self = (SDLBridge*)userData;
-
- // safety checks
- DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr,);
- DISTRHO_SAFE_ASSERT_RETURN(len > 0,);
-
- if (self->jackProcessCallback == nullptr)
- {
- std::memset(stream, 0, len);
- return;
- }
-
- const uint numFrames = static_cast<uint>(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;
-
- for (uint i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
- {
- for (uint j=0; j < numFrames; ++j)
- fstream[j * DISTRHO_PLUGIN_NUM_OUTPUTS + i] = self->audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i][j];
- }
- }
-#endif
-};
-
-#endif
diff --git a/distrho/src/jackbridge/WebBridge.hpp b/distrho/src/jackbridge/WebBridge.hpp
@@ -0,0 +1,354 @@
+/*
+ * Web Audio + MIDI Bridge for DPF
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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 <emscripten/emscripten.h>
+
+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<WebBridge*>(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; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
+ std::memset(self->audioBuffers[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<WebBridge*>(userData);
+
+ // TODO timestamp handling
+ self->midiInBufferPending.writeByte(static_cast<uint8_t>(len));
+ self->midiInBufferPending.writeCustomData(data, kMaxMIDIInputMessageSize);
+ self->midiInBufferPending.commitWrite();
+ }
+ #endif
+};
+
+#endif // WEB_BRIDGE_HPP_INCLUDED