DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit ceaea6080f6a704a0c992c766e28d7cdb4901f11
parent f022c766bd315b5bb22800b9ab78a4e1ec991edc
Author: falkTX <falktx@falktx.com>
Date:   Sun, 10 Jul 2022 17:59:48 +0100

Rework SDL bridge to support audio input

Signed-off-by: falkTX <falktx@falktx.com>

Diffstat:
Mdistrho/src/jackbridge/JackBridge.cpp | 2+-
Mdistrho/src/jackbridge/SDLBridge.hpp | 182++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 145 insertions(+), 39 deletions(-)

diff --git a/distrho/src/jackbridge/JackBridge.cpp b/distrho/src/jackbridge/JackBridge.cpp @@ -36,7 +36,7 @@ #include "../../extra/LibraryUtils.hpp" // in case JACK fails, we fallback to RtAudio or SDL native API -#if defined(DISTRHO_OS_WASM) +#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) # include "RtAudioBridge.hpp" diff --git a/distrho/src/jackbridge/SDLBridge.hpp b/distrho/src/jackbridge/SDLBridge.hpp @@ -23,7 +23,12 @@ #include <SDL.h> struct SDLBridge { - SDL_AudioDeviceID deviceId = 0; +#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; @@ -61,37 +66,97 @@ struct SDLBridge { bool open(const char* const clientName) { - SDL_AudioSpec requested, received; + #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.channels = DISTRHO_PLUGIN_NUM_OUTPUTS; requested.freq = 48000; requested.samples = 512; - requested.callback = SDLCallback; requested.userdata = this; SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, clientName); - // SDL_SetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME, ); SDL_SetHint(SDL_HINT_AUDIO_RESAMPLING_MODE, "2"); + #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; - /* - deviceId = SDL_OpenAudioDevice("PulseAudio", 0, - &requested, &received, - SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); - */ - deviceId = SDL_OpenAudio(&requested, &received) == 0 ? 1 : 0; - DISTRHO_SAFE_ASSERT_RETURN(deviceId != 0, false); + 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; - if (received.channels != DISTRHO_PLUGIN_NUM_OUTPUTS) + playbackDeviceId = SDL_OpenAudioDevice(nullptr, 0, &requested, &receivedPlayback, + SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE); + if (playbackDeviceId == 0) { - SDL_CloseAudioDevice(deviceId); - deviceId = 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 - bufferSize = received.samples; - sampleRate = received.freq; #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 audioBufferStorage = new float[bufferSize*(DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS)]; @@ -108,11 +173,16 @@ struct SDLBridge { bool close() { - DISTRHO_SAFE_ASSERT_RETURN(deviceId != 0, false); - - // SDL_CloseAudioDevice(deviceId); - SDL_CloseAudio(); - deviceId = 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 + 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; @@ -124,17 +194,27 @@ struct SDLBridge { bool activate() { - DISTRHO_SAFE_ASSERT_RETURN(deviceId != 0, false); - - SDL_PauseAudioDevice(deviceId, 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 + DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false); + SDL_PauseAudioDevice(playbackDeviceId, 0); +#endif return true; } bool deactivate() { - DISTRHO_SAFE_ASSERT_RETURN(deviceId != 0, false); - - SDL_PauseAudioDevice(deviceId, 1); +#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; } @@ -184,7 +264,8 @@ struct SDLBridge { return nullptr; } - static void SDLCallback(void* const userData, uchar* const stream, const int len) +#if DISTRHO_PLUGIN_NUM_INPUTS > 0 + static void AudioInputCallback(void* const userData, uchar* const stream, const int len) { SDLBridge* const self = (SDLBridge*)userData; @@ -192,29 +273,54 @@ struct SDLBridge { DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr,); DISTRHO_SAFE_ASSERT_RETURN(len > 0,); - float* const fstream = (float*)stream; + 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 + if (self->jackProcessCallback != nullptr) + 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) + { + SDLBridge* const self = (SDLBridge*)userData; + + // safety checks + DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(len > 0,); -// #if DISTRHO_PLUGIN_NUM_OUTPUTS == 0 if (self->jackProcessCallback == nullptr) -// #endif { - std::memset(fstream, 0, len); + std::memset(stream, 0, len); return; } -// #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - const uint numFrames = static_cast<uint>(static_cast<uint>(len) / sizeof(float) / DISTRHO_PLUGIN_NUM_OUTPUTS); + const uint numFrames = static_cast<uint>(len / sizeof(float) / DISTRHO_PLUGIN_NUM_OUTPUTS); + DISTRHO_SAFE_ASSERT_UINT2_RETURN(numFrames == self->bufferSize, numFrames, self->bufferSize,); + + float* const fstream = (float*)stream; self->jackProcessCallback(numFrames, self->jackProcessArg); 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]; + fstream[j * DISTRHO_PLUGIN_NUM_OUTPUTS + i] = self->audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i][j]; } -// #endif } - +#endif }; #endif