Mercurial > hg > pub > prymula > com
diff DPF-Prymula-audioplugins/dpf/distrho/src/jackbridge/SDL2Bridge.hpp @ 3:84e66ea83026
DPF-Prymula-audioplugins-0.231015-2
author | prymula <prymula76@outlook.com> |
---|---|
date | Mon, 16 Oct 2023 21:53:34 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DPF-Prymula-audioplugins/dpf/distrho/src/jackbridge/SDL2Bridge.hpp Mon Oct 16 21:53:34 2023 +0200 @@ -0,0 +1,265 @@ +/* + * SDL Bridge for DPF + * Copyright (C) 2021-2023 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 "../../extra/ScopedDenormalDisable.hpp" + +#include <SDL.h> + +#ifndef SDL_HINT_AUDIO_DEVICE_APP_NAME +# define SDL_HINT_AUDIO_DEVICE_APP_NAME "SDL_AUDIO_DEVICE_APP_NAME" +#endif + +#ifndef SDL_HINT_AUDIO_DEVICE_STREAM_NAME +# define SDL_HINT_AUDIO_DEVICE_STREAM_NAME "SDL_AUDIO_DEVICE_STREAM_NAME" +#endif + +#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; + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + SDL_AudioDeviceID playbackDeviceId; + #endif + + SDL2Bridge() + : NativeBridge() + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + , captureDeviceId(0) + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + , 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_2; + 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 capture device, error was: %s", SDL_GetError()); + #if DISTRHO_PLUGIN_NUM_OUTPUTS == 0 + return false; + #endif + } + else if (receivedCapture.channels != DISTRHO_PLUGIN_NUM_INPUTS_2) + { + 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_2; + 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_2) + { + 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 && captureDeviceId != 0) + { + SDL_CloseAudioDevice(captureDeviceId); + SDL_CloseAudioDevice(playbackDeviceId); + captureDeviceId = playbackDeviceId = 0; + d_stderr2("Mismatch buffer size %u vs %u", receivedCapture.samples, receivedPlayback.samples); + return false; + } + if (receivedCapture.freq != receivedPlayback.freq && captureDeviceId != 0) + { + SDL_CloseAudioDevice(captureDeviceId); + SDL_CloseAudioDevice(playbackDeviceId); + captureDeviceId = playbackDeviceId = 0; + d_stderr2("Mismatch sample rate %u vs %u", receivedCapture.freq, receivedPlayback.freq); + return false; + } + #endif + + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + if (captureDeviceId != 0) + { + bufferSize = receivedCapture.samples; + sampleRate = receivedCapture.freq; + } + #endif + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 && DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + else + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + { + bufferSize = receivedPlayback.samples; + sampleRate = receivedPlayback.freq; + } + #endif + + allocBuffers(true, false); + return true; + } + + bool close() override + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + if (captureDeviceId != 0) + { + 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 + if (captureDeviceId != 0) + 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 + if (captureDeviceId != 0) + 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_2); + 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_2; ++i) + { + for (uint j=0; j<numFrames; ++j) + self->audioBuffers[i][j] = fstream[j * DISTRHO_PLUGIN_NUM_INPUTS_2 + i]; + } + + #if DISTRHO_PLUGIN_NUM_OUTPUTS == 0 + // if there are no outputs, run process callback now + const ScopedDenormalDisable sdd; + 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_2); + DISTRHO_SAFE_ASSERT_UINT2_RETURN(numFrames == self->bufferSize, numFrames, self->bufferSize,); + + const ScopedDenormalDisable sdd; + self->jackProcessCallback(numFrames, self->jackProcessArg); + + float* const fstream = (float*)stream; + + for (uint i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS_2; ++i) + { + for (uint j=0; j < numFrames; ++j) + fstream[j * DISTRHO_PLUGIN_NUM_OUTPUTS_2 + i] = self->audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i][j]; + } + } + #endif +}; + +#endif // SDL_BRIDGE_HPP_INCLUDED