From 70d2f63accbdff61765dc31bde42613ba0d12a71 Mon Sep 17 00:00:00 2001 From: falkTX Date: Thu, 21 Oct 2021 22:53:45 +0100 Subject: [PATCH] Add MIDI input driver Signed-off-by: falkTX --- src/CardinalPlugin.cpp | 48 ++++++- src/DistrhoPluginInfo.h | 2 + src/PluginContext.hpp | 131 +---------------- src/PluginDriver.hpp | 312 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 366 insertions(+), 127 deletions(-) create mode 100644 src/PluginDriver.hpp diff --git a/src/CardinalPlugin.cpp b/src/CardinalPlugin.cpp index 164c7ee..c4e3c5e 100644 --- a/src/CardinalPlugin.cpp +++ b/src/CardinalPlugin.cpp @@ -35,8 +35,11 @@ # undef DEBUG #endif +#include +#include + #include "DistrhoPluginUtils.hpp" -#include "PluginContext.hpp" +#include "PluginDriver.hpp" #include "WindowParameters.hpp" #include "extra/Base64.hpp" #include "extra/SharedResourcePointer.hpp" @@ -119,6 +122,9 @@ struct Initializer { INFO("Initializing audio driver"); rack::audio::addDriver(0, new CardinalAudioDriver); + INFO("Initializing midi driver"); + rack::midi::addDriver(0, new CardinalMidiDriver); + INFO("Initializing plugins"); plugin::initStaticPlugins(); } @@ -170,8 +176,11 @@ class CardinalPlugin : public CardinalBasePlugin // for base/context handling bool fIsActive; + std::atomic fIsProcessing; rack::audio::Device* fCurrentDevice; Mutex fDeviceMutex; + std::list fMidiInputs; + volatile pthread_t fProcessThread; float fWindowParameters[kWindowParameterCount]; @@ -182,7 +191,13 @@ public: fAudioBufferIn(nullptr), fAudioBufferOut(nullptr), fIsActive(false), - fCurrentDevice(nullptr) + fIsProcessing(false), + fCurrentDevice(nullptr), +#ifdef PTW32_DLLPORT + fProcessThread({nullptr, 0}) +#else + fProcessThread(0) +#endif { fWindowParameters[kWindowParameterCableOpacity] = 50.0f; fWindowParameters[kWindowParameterCableTension] = 50.0f; @@ -260,6 +275,11 @@ protected: return fIsActive; } + bool isProcessing() const noexcept override + { + return fIsProcessing.load() && pthread_equal(fProcessThread, pthread_self() != 0); + } + bool canAssignDevice() const noexcept override { const MutexLocker cml(fDeviceMutex); @@ -285,6 +305,19 @@ protected: return true; } + void addMidiInput(CardinalMidiInputDevice* const dev) override + { + const MutexLocker cml(fDeviceMutex); + + fMidiInputs.push_back(dev); + } + + void removeMidiInput(CardinalMidiInputDevice* const dev) override + { + const MutexLocker cml(fDeviceMutex); + + } + /* -------------------------------------------------------------------------------------------------------- * Information */ @@ -498,13 +531,16 @@ protected: fAudioBufferIn = fAudioBufferOut = nullptr; } - void run(const float** const inputs, float** const outputs, const uint32_t frames) override + void run(const float** const inputs, float** const outputs, const uint32_t frames, + const MidiEvent* const midiEvents, const uint32_t midiEventCount) override { /* context->engine->setFrame(getTimePosition().frame); context->engine->stepBlock(frames); */ + fProcessThread = pthread_self(); + const MutexLocker cml(fDeviceMutex); // const MutexTryLocker cmtl(fPatchMutex); @@ -523,8 +559,14 @@ protected: std::memset(fAudioBufferOut, 0, sizeof(float)*frames*DISTRHO_PLUGIN_NUM_OUTPUTS); + fIsProcessing.store(1); + + for (CardinalMidiInputDevice* dev : fMidiInputs) + dev->handleMessagesFromHost(midiEvents, midiEventCount); + fCurrentDevice->processBuffer(fAudioBufferIn, DISTRHO_PLUGIN_NUM_INPUTS, fAudioBufferOut, DISTRHO_PLUGIN_NUM_OUTPUTS, frames); + fIsProcessing.store(0); for (uint32_t i=0, j=0; i #include +#include #ifdef NDEBUG # undef DEBUG @@ -54,6 +55,9 @@ struct CardinalPluginContext : rack::Context { // ----------------------------------------------------------------------------------------------------------- +struct CardinalMidiInputDevice; +struct CardinalMidiOutputDevice; + class CardinalBasePlugin : public Plugin { public: CardinalPluginContext* const context; @@ -63,9 +67,12 @@ public: context(new CardinalPluginContext(this)) {} ~CardinalBasePlugin() override {} virtual bool isActive() const noexcept = 0; + virtual bool isProcessing() 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; + virtual void addMidiInput(CardinalMidiInputDevice* dev) = 0; + virtual void removeMidiInput(CardinalMidiInputDevice* dev) = 0; protected: void bufferSizeChanged(const uint32_t newBufferSize) override @@ -82,128 +89,4 @@ protected: // ----------------------------------------------------------------------------------------------------------- -struct CardinalAudioDevice : rack::audio::Device { - CardinalBasePlugin* const fPlugin; - - CardinalAudioDevice(CardinalBasePlugin* const plugin) - : fPlugin(plugin) {} - - std::string getName() override - { - return "Cardinal"; - } - - 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 }); - } - - int getDefaultDeviceId() override - { - return 0; - } - - std::string getDeviceName(int) override - { - return "Plugin 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 = reinterpret_cast(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 = reinterpret_cast(pluginContext->plugin); - DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); - - if (plugin->clearDevice(device)) - { - device->onStopStream(); - device->unsubscribe(port); - delete device; - } - } -}; - -// ----------------------------------------------------------------------------------------------------------- - END_NAMESPACE_DISTRHO diff --git a/src/PluginDriver.hpp b/src/PluginDriver.hpp new file mode 100644 index 0000000..e204a34 --- /dev/null +++ b/src/PluginDriver.hpp @@ -0,0 +1,312 @@ +/* + * 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 "PluginContext.hpp" + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- + +struct CardinalAudioDevice : rack::audio::Device +{ + CardinalBasePlugin* const fPlugin; + + CardinalAudioDevice(CardinalBasePlugin* const plugin) + : fPlugin(plugin) {} + + std::string getName() override + { + return "Cardinal"; + } + + 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 }); + } + + int getDefaultDeviceId() override + { + return 0; + } + + std::string getDeviceName(int) override + { + return "Plugin 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 = reinterpret_cast(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 = reinterpret_cast(pluginContext->plugin); + DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); + + if (plugin->clearDevice(device)) + { + device->onStopStream(); + device->unsubscribe(port); + delete device; + } + } +}; + +// ----------------------------------------------------------------------------------------------------------- + +struct CardinalMidiInputDevice : rack::midi::InputDevice +{ + CardinalBasePlugin* const fPlugin; + rack::midi::Message msg; + + CardinalMidiInputDevice(CardinalBasePlugin* const plugin) + : fPlugin(plugin) + { + msg.bytes.reserve(0xff); + } + + std::string getName() override + { + return "Cardinal"; + } + + void handleMessagesFromHost(const MidiEvent* const midiEvents, const uint32_t midiEventCount) + { + if (subscribed.size() == 0) + return; + + for (uint32_t i=0; i MidiEvent::kDataSize) + { + data = midiEvent.dataExt; + msg.bytes.reserve(midiEvent.size); + } + else + { + data = midiEvent.data; + } + + msg.frame = midiEvent.frame; + std::memcpy(msg.bytes.data(), data, midiEvent.size); + + onMessage(msg); + } + } +}; + +// ----------------------------------------------------------------------------------------------------------- + +struct CardinalMidiOutputDevice : rack::midi::OutputDevice +{ + CardinalBasePlugin* const fPlugin; + + CardinalMidiOutputDevice(CardinalBasePlugin* const plugin) + : fPlugin(plugin) {} + + std::string getName() override + { + return "Cardinal"; + } + + void sendMessage(const rack::midi::Message& message) override + { + } +}; + +// ----------------------------------------------------------------------------------------------------------- + +struct CardinalMidiDriver : rack::midi::Driver +{ + CardinalMidiDriver() {} + + std::string getName() override + { + return "Plugin Driver"; + } + + std::vector getInputDeviceIds() override + { + return std::vector({ 0 }); + } + + std::vector getOutputDeviceIds() override + { + return std::vector({ 0 }); + } + + int getDefaultInputDeviceId() override + { + return 0; + } + + int getDefaultOutputDeviceId() override + { + return 0; + } + + std::string getInputDeviceName(int) override + { + return "Plugin Device"; + } + + std::string getOutputDeviceName(int) override + { + return "Plugin Device"; + } + + rack::midi::InputDevice* subscribeInput(int, rack::midi::Input* const input) override + { + CardinalPluginContext* const pluginContext = reinterpret_cast(input->context); + DISTRHO_SAFE_ASSERT_RETURN(pluginContext != nullptr, nullptr); + + CardinalBasePlugin* const plugin = reinterpret_cast(pluginContext->plugin); + DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, nullptr); + + CardinalMidiInputDevice* const device = new CardinalMidiInputDevice(plugin); + device->subscribe(input); + + plugin->addMidiInput(device); + return device; + } + + rack::midi::OutputDevice* subscribeOutput(int, rack::midi::Output* const output) override + { + CardinalPluginContext* const pluginContext = reinterpret_cast(output->context); + DISTRHO_SAFE_ASSERT_RETURN(pluginContext != nullptr, nullptr); + + CardinalBasePlugin* const plugin = reinterpret_cast(pluginContext->plugin); + DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, nullptr); + + CardinalMidiOutputDevice* const device = new CardinalMidiOutputDevice(plugin); + device->subscribe(output); + + return device; + } + + void unsubscribeInput(int, rack::midi::Input* const input) override + { + CardinalMidiInputDevice* const device = reinterpret_cast(input->device); + DISTRHO_SAFE_ASSERT_RETURN(device != nullptr,); + + CardinalPluginContext* const pluginContext = reinterpret_cast(input->context); + DISTRHO_SAFE_ASSERT_RETURN(pluginContext != nullptr,); + + CardinalBasePlugin* const plugin = reinterpret_cast(pluginContext->plugin); + DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); + + plugin->removeMidiInput(device); + device->unsubscribe(input); + delete device; + } + + void unsubscribeOutput(int, rack::midi::Output* const output) override + { + CardinalMidiOutputDevice* const device = reinterpret_cast(output->device); + DISTRHO_SAFE_ASSERT_RETURN(device != nullptr,); + + device->unsubscribe(output); + delete device; + } +}; + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO