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