From e0e50db2bc5a31af45c04d33c8b06321aed09a2c Mon Sep 17 00:00:00 2001 From: falkTX Date: Mon, 18 Oct 2021 02:25:35 +0100 Subject: [PATCH] Rework to allow multi-context audio, custom driver, custom context Signed-off-by: falkTX --- src/CardinalPlugin.cpp | 192 +++++++++++++---------------------------- src/CardinalUI.cpp | 9 +- src/PluginContext.hpp | 174 +++++++++++++++++++++++++++++++++++++ 3 files changed, 240 insertions(+), 135 deletions(-) create mode 100644 src/PluginContext.hpp diff --git a/src/CardinalPlugin.cpp b/src/CardinalPlugin.cpp index 1512c7f..1d5140f 100644 --- a/src/CardinalPlugin.cpp +++ b/src/CardinalPlugin.cpp @@ -16,14 +16,11 @@ */ #include -#include -#include #include #include #include #include #include -// #include #include #include @@ -34,11 +31,7 @@ #include -#ifdef NDEBUG -# undef DEBUG -#endif - -#include "DistrhoPlugin.hpp" +#include "PluginContext.hpp" namespace rack { namespace plugin { @@ -50,15 +43,6 @@ void destroyStaticPlugins(); START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------------------------------------------- -// The following code was based from VCVRack adapters/standalone.cpp - -/* - Copyright (C) 2016-2021 VCV - - This program is free software: you can redistribute it and/or modify it under the terms of the - GNU General Public License as published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. -*/ struct Initializer { Initializer() @@ -98,7 +82,9 @@ struct Initializer { INFO("Initializing environment"); audio::init(); // does nothing midi::init(); // does nothing - // rtaudioInit(); + + rack::audio::addDriver(0, new CardinalAudioDriver); + plugin::initStaticPlugins(); ui::init(); } @@ -127,111 +113,17 @@ static const Initializer& getInitializerInstance() // ----------------------------------------------------------------------------------------------------------- -struct CardinalAudioDevice : rack::audio::Device { - Plugin* const fPlugin; - - CardinalAudioDevice(Plugin* const plugin) - : fPlugin(plugin) {} - - std::string getName() override - { - return "Plugin Device"; - } - - int getNumInputs() override - { - return DISTRHO_PLUGIN_NUM_INPUTS; - } - - int getNumOutputs() override - { - return DISTRHO_PLUGIN_NUM_OUTPUTS; - } - - std::set getSampleRates() override - { - return { getSampleRate() }; - } - - float getSampleRate() override - { - return fPlugin->getSampleRate(); - } - - void setSampleRate(float) override {} - - std::set getBlockSizes() override - { - return { getBlockSize() }; - } - - int getBlockSize() override - { - return fPlugin->getBufferSize(); - } - - void setBlockSize(int) override {} -}; - -// ----------------------------------------------------------------------------------------------------------- - -struct CardinalAudioDriver : rack::audio::Driver { - Plugin* const fPlugin; - CardinalAudioDevice fDevice; - - CardinalAudioDriver(Plugin* const plugin) - : fPlugin(plugin), - fDevice(plugin) {} - - std::string getName() override - { - return "Plugin Driver"; - } - - std::vector getDeviceIds() override - { - return { 0 }; - } - - std::string getDeviceName(int) override - { - return "Plugin Driver Device"; - } - - int getDeviceNumInputs(int) override - { - return DISTRHO_PLUGIN_NUM_INPUTS; - } - - int getDeviceNumOutputs(int) override - { - return DISTRHO_PLUGIN_NUM_OUTPUTS; - } - - rack::audio::Device* subscribe(int, rack::audio::Port* const port) override - { - fDevice.subscribe(port); - fDevice.onStartStream(); - return &fDevice; - } - - void unsubscribe(int, rack::audio::Port* const port) override - { - fDevice.onStopStream(); - fDevice.unsubscribe(port); - } -}; - -// ----------------------------------------------------------------------------------------------------------- - -class CardinalPlugin : public Plugin +class CardinalPlugin : public CardinalBasePlugin { - rack::Context* const fContext; - CardinalAudioDriver* const fAudioDriver; + CardinalPluginContext* const fContext; float* fAudioBufferIn; float* fAudioBufferOut; std::string fAutosavePath; + // for base/context handling + bool fIsActive; + rack::audio::Device* fCurrentDevice; + struct ScopedContext { ScopedContext(CardinalPlugin* const plugin) { @@ -246,11 +138,12 @@ class CardinalPlugin : public Plugin public: CardinalPlugin() - : Plugin(0, 0, 0), - fContext(new rack::Context), - fAudioDriver(new CardinalAudioDriver(this)), + : CardinalBasePlugin(0, 0, 0), + fContext(new CardinalPluginContext(this)), fAudioBufferIn(nullptr), - fAudioBufferOut(nullptr) + fAudioBufferOut(nullptr), + fIsActive(false), + fCurrentDevice(nullptr) { // create unique temporary path for this instance try { @@ -273,8 +166,6 @@ public: const ScopedContext sc(this); - rack::audio::addDriver(0, fAudioDriver); - fContext->engine = new rack::engine::Engine; fContext->history = new rack::history::State; fContext->patch = new rack::patch::Manager; @@ -288,19 +179,47 @@ public: { const ScopedContext sc(this); delete fContext; - // rack::audio::destroy(); } if (! fAutosavePath.empty()) rack::system::removeRecursively(fAutosavePath); } - rack::Context* getRackContext() const noexcept + CardinalPluginContext* getRackContext() const noexcept { return fContext; } protected: + /* -------------------------------------------------------------------------------------------------------- + * Cardinal Base things */ + + bool isActive() const noexcept override + { + return fIsActive; + } + + bool canAssignDevice() const noexcept override + { + return fCurrentDevice == nullptr; + } + + void assignDevice(rack::audio::Device* const dev) noexcept override + { + DISTRHO_SAFE_ASSERT_RETURN(fCurrentDevice == nullptr,); + + fCurrentDevice = dev; + } + + bool clearDevice(rack::audio::Device* const dev) noexcept override + { + if (fCurrentDevice != dev) + return false; + + fCurrentDevice = dev; + return true; + } + /* -------------------------------------------------------------------------------------------------------- * Information */ @@ -378,11 +297,15 @@ protected: fAudioBufferIn = new float[bufferSize]; fAudioBufferOut = new float[bufferSize]; std::memset(fAudioBufferIn, 0, sizeof(float)*bufferSize); + + if (fCurrentDevice != nullptr) + fCurrentDevice->onStartStream(); } void deactivate() override { - fAudioDriver->fDevice.onStopStream(); + if (fCurrentDevice != nullptr) + fCurrentDevice->onStopStream(); delete[] fAudioBufferIn; delete[] fAudioBufferOut; @@ -399,6 +322,15 @@ protected: fContext->engine->stepBlock(frames); */ + if (fCurrentDevice == nullptr) + { + if (outputs[0] != inputs[0]) + std::memcpy(outputs[0], inputs[0], sizeof(float)*frames); + if (outputs[1] != inputs[1]) + std::memcpy(outputs[1], inputs[1], sizeof(float)*frames); + return; + } + for (uint32_t i=0, j=0; ifDevice.processBuffer(fAudioBufferIn, DISTRHO_PLUGIN_NUM_INPUTS, - fAudioBufferOut, DISTRHO_PLUGIN_NUM_OUTPUTS, frames); + fCurrentDevice->processBuffer(fAudioBufferIn, DISTRHO_PLUGIN_NUM_INPUTS, + fAudioBufferOut, DISTRHO_PLUGIN_NUM_OUTPUTS, frames); for (uint32_t i=0, j=0; i(ptr)->getRackContext(); } diff --git a/src/CardinalUI.cpp b/src/CardinalUI.cpp index 95505a5..783ada1 100644 --- a/src/CardinalUI.cpp +++ b/src/CardinalUI.cpp @@ -21,9 +21,8 @@ #include #include -#ifdef NDEBUG -# undef DEBUG -#endif +#include "PluginContext.hpp" + #include "DistrhoUI.hpp" #include "ResizeHandle.hpp" @@ -42,11 +41,11 @@ START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------------------------------------------- -rack::Context* getRackContextFromPlugin(void* ptr); +CardinalPluginContext* getRackContextFromPlugin(void* ptr); class CardinalUI : public UI { - rack::Context* const fContext; + CardinalPluginContext* const fContext; rack::math::Vec fLastMousePos; ResizeHandle fResizeHandle; diff --git a/src/PluginContext.hpp b/src/PluginContext.hpp new file mode 100644 index 0000000..99aea4f --- /dev/null +++ b/src/PluginContext.hpp @@ -0,0 +1,174 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#pragma once + +#include +#include + +#ifdef NDEBUG +# undef DEBUG +#endif + +#include "DistrhoPlugin.hpp" + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- + +class CardinalBasePlugin : public Plugin { +public: + CardinalBasePlugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCount) + : Plugin(parameterCount, programCount, stateCount) {} + ~CardinalBasePlugin() override {} + virtual bool isActive() const noexcept = 0; + virtual bool canAssignDevice() const noexcept = 0; + virtual void assignDevice(rack::audio::Device* dev) noexcept = 0; + virtual bool clearDevice(rack::audio::Device* dev) noexcept = 0; +}; + +// ----------------------------------------------------------------------------------------------------------- + +struct CardinalPluginContext : rack::Context { + CardinalBasePlugin* const plugin; + + CardinalPluginContext(CardinalBasePlugin* const p) + : plugin(p) {} +}; + +// ----------------------------------------------------------------------------------------------------------- + +struct CardinalAudioDevice : rack::audio::Device { + CardinalBasePlugin* const fPlugin; + + CardinalAudioDevice(CardinalBasePlugin* const plugin) + : fPlugin(plugin) {} + + std::string getName() override + { + return "Plugin Device"; + } + + int getNumInputs() override + { + return DISTRHO_PLUGIN_NUM_INPUTS; + } + + int getNumOutputs() override + { + return DISTRHO_PLUGIN_NUM_OUTPUTS; + } + + int getBlockSize() override + { + return fPlugin->getBufferSize(); + } + + float getSampleRate() override + { + return fPlugin->getSampleRate(); + } + + std::set getBlockSizes() override + { + return std::set({ getBlockSize() }); + } + + std::set getSampleRates() override + { + return std::set({ getSampleRate() }); + } + + void setBlockSize(int) override {} + void setSampleRate(float) override {} +}; + +// ----------------------------------------------------------------------------------------------------------- + +struct CardinalAudioDriver : rack::audio::Driver { + + CardinalAudioDriver() {} + + std::string getName() override + { + return "Plugin Driver"; + } + + std::vector getDeviceIds() override + { + return std::vector({ 0 }); + } + + std::string getDeviceName(int) override + { + return "Plugin Driver Device"; + } + + int getDeviceNumInputs(int) override + { + return DISTRHO_PLUGIN_NUM_INPUTS; + } + + int getDeviceNumOutputs(int) override + { + return DISTRHO_PLUGIN_NUM_OUTPUTS; + } + + rack::audio::Device* subscribe(int, rack::audio::Port* const port) override + { + CardinalPluginContext* const pluginContext = reinterpret_cast(port->context); + DISTRHO_SAFE_ASSERT_RETURN(pluginContext != nullptr, nullptr); + + CardinalBasePlugin* const plugin = pluginContext->plugin; + DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, nullptr); + + if (! plugin->canAssignDevice()) + throw rack::Exception("Plugin driver only allows one audio device to be used simultaneously"); + + CardinalAudioDevice* const device = new CardinalAudioDevice(plugin); + device->subscribe(port); + + if (plugin->isActive()) + device->onStartStream(); + + plugin->assignDevice(device); + return device; + } + + void unsubscribe(int, rack::audio::Port* const port) override + { + CardinalAudioDevice* const device = reinterpret_cast(port->device); + DISTRHO_SAFE_ASSERT_RETURN(device != nullptr,); + + CardinalPluginContext* const pluginContext = reinterpret_cast(port->context); + DISTRHO_SAFE_ASSERT_RETURN(pluginContext != nullptr,); + + CardinalBasePlugin* const plugin = pluginContext->plugin; + DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); + + if (plugin->clearDevice(device)) + { + device->onStopStream(); + device->unsubscribe(port); + delete device; + } + } +}; + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO