From 738a0c820e465a6feda0553f079f6301f5e657e8 Mon Sep 17 00:00:00 2001 From: falkTX Date: Thu, 21 Oct 2021 23:54:04 +0100 Subject: [PATCH] Alternative MIDI output approach that works Signed-off-by: falkTX --- src/CardinalPlugin.cpp | 105 +++++++++++++++++++++++------------------ src/PluginContext.hpp | 11 +++-- src/PluginDriver.hpp | 54 ++++++++++++++++----- 3 files changed, 109 insertions(+), 61 deletions(-) diff --git a/src/CardinalPlugin.cpp b/src/CardinalPlugin.cpp index c4e3c5e..1beeadc 100644 --- a/src/CardinalPlugin.cpp +++ b/src/CardinalPlugin.cpp @@ -35,7 +35,6 @@ # undef DEBUG #endif -#include #include #include "DistrhoPluginUtils.hpp" @@ -176,11 +175,10 @@ class CardinalPlugin : public CardinalBasePlugin // for base/context handling bool fIsActive; - std::atomic fIsProcessing; - rack::audio::Device* fCurrentDevice; - Mutex fDeviceMutex; + CardinalAudioDevice* fCurrentAudioDevice; + CardinalMidiOutputDevice* fCurrentMidiOutput; std::list fMidiInputs; - volatile pthread_t fProcessThread; + Mutex fDeviceMutex; float fWindowParameters[kWindowParameterCount]; @@ -191,13 +189,8 @@ public: fAudioBufferIn(nullptr), fAudioBufferOut(nullptr), fIsActive(false), - fIsProcessing(false), - fCurrentDevice(nullptr), -#ifdef PTW32_DLLPORT - fProcessThread({nullptr, 0}) -#else - fProcessThread(0) -#endif + fCurrentAudioDevice(nullptr), + fCurrentMidiOutput(nullptr) { fWindowParameters[kWindowParameterCableOpacity] = 50.0f; fWindowParameters[kWindowParameterCableTension] = 50.0f; @@ -275,38 +268,59 @@ protected: return fIsActive; } - bool isProcessing() const noexcept override - { - return fIsProcessing.load() && pthread_equal(fProcessThread, pthread_self() != 0); - } - - bool canAssignDevice() const noexcept override + bool canAssignAudioDevice() const noexcept override { const MutexLocker cml(fDeviceMutex); - return fCurrentDevice == nullptr; + return fCurrentAudioDevice == nullptr; } - void assignDevice(rack::audio::Device* const dev) noexcept override + bool canAssignMidiOutputDevice() const noexcept override { - DISTRHO_SAFE_ASSERT_RETURN(fCurrentDevice == nullptr,); + const MutexLocker cml(fDeviceMutex); + return fCurrentMidiOutput == nullptr; + } + + void assignAudioDevice(CardinalAudioDevice* const dev) noexcept override + { + DISTRHO_SAFE_ASSERT_RETURN(fCurrentAudioDevice == nullptr,); const MutexLocker cml(fDeviceMutex); - fCurrentDevice = dev; + fCurrentAudioDevice = dev; } - bool clearDevice(rack::audio::Device* const dev) noexcept override + void assignMidiOutputDevice(CardinalMidiOutputDevice* const dev) noexcept override + { + DISTRHO_SAFE_ASSERT_RETURN(fCurrentMidiOutput == nullptr,); + + const MutexLocker cml(fDeviceMutex); + fCurrentMidiOutput = dev; + } + + bool clearAudioDevice(CardinalAudioDevice* const dev) noexcept override { const MutexLocker cml(fDeviceMutex); - if (fCurrentDevice != dev) + if (fCurrentAudioDevice != dev) return false; - fCurrentDevice = nullptr; + fCurrentAudioDevice = nullptr; + return true; + } + + bool clearMidiOutputDevice(CardinalMidiOutputDevice* const dev) noexcept override + { + const MutexLocker cml(fDeviceMutex); + + if (fCurrentMidiOutput != dev) + return false; + + fCurrentMidiOutput = nullptr; return true; } void addMidiInput(CardinalMidiInputDevice* const dev) override { + // NOTE this will xrun const MutexLocker cml(fDeviceMutex); fMidiInputs.push_back(dev); @@ -314,8 +328,10 @@ protected: void removeMidiInput(CardinalMidiInputDevice* const dev) override { + // NOTE this will xrun const MutexLocker cml(fDeviceMutex); + fMidiInputs.remove(dev); } /* -------------------------------------------------------------------------------------------------------- @@ -512,8 +528,8 @@ protected: { const MutexLocker cml(fDeviceMutex); - if (fCurrentDevice != nullptr) - fCurrentDevice->onStartStream(); + if (fCurrentAudioDevice != nullptr) + fCurrentAudioDevice->onStartStream(); } } @@ -522,8 +538,8 @@ protected: { const MutexLocker cml(fDeviceMutex); - if (fCurrentDevice != nullptr) - fCurrentDevice->onStopStream(); + if (fCurrentAudioDevice != nullptr) + fCurrentAudioDevice->onStopStream(); } delete[] fAudioBufferIn; @@ -539,34 +555,33 @@ protected: context->engine->stepBlock(frames); */ - fProcessThread = pthread_self(); - const MutexLocker cml(fDeviceMutex); - // const MutexTryLocker cmtl(fPatchMutex); - if (fCurrentDevice == nullptr /*|| cmtl.wasNotLocked()*/) + if (fCurrentAudioDevice != nullptr) + { + for (uint32_t i=0, j=0; ihandleMessagesFromHost(midiEvents, midiEventCount); - fCurrentDevice->processBuffer(fAudioBufferIn, DISTRHO_PLUGIN_NUM_INPUTS, - fAudioBufferOut, DISTRHO_PLUGIN_NUM_OUTPUTS, frames); - fIsProcessing.store(0); + if (fCurrentAudioDevice != nullptr) + fCurrentAudioDevice->processBuffer(fAudioBufferIn, DISTRHO_PLUGIN_NUM_INPUTS, + fAudioBufferOut, DISTRHO_PLUGIN_NUM_OUTPUTS, frames); + + if (fCurrentMidiOutput != nullptr) + fCurrentMidiOutput->processMessages(); for (uint32_t i=0, j=0; i(pluginContext->plugin); DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, nullptr); - if (! plugin->canAssignDevice()) + if (! plugin->canAssignAudioDevice()) throw rack::Exception("Plugin driver only allows one audio device to be used simultaneously"); CardinalAudioDevice* const device = new CardinalAudioDevice(plugin); @@ -122,7 +122,7 @@ struct CardinalAudioDriver : rack::audio::Driver if (plugin->isActive()) device->onStartStream(); - plugin->assignDevice(device); + plugin->assignAudioDevice(device); return device; } @@ -137,7 +137,7 @@ struct CardinalAudioDriver : rack::audio::Driver CardinalBasePlugin* const plugin = reinterpret_cast(pluginContext->plugin); DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); - if (plugin->clearDevice(device)) + if (plugin->clearAudioDevice(device)) { device->onStopStream(); device->unsubscribe(port); @@ -197,27 +197,44 @@ struct CardinalMidiInputDevice : rack::midi::InputDevice struct CardinalMidiOutputDevice : rack::midi::OutputDevice { CardinalBasePlugin* const fPlugin; + MidiEvent fQueue[128]; + Mutex fQueueMutex; + uint8_t fQueueIndex; CardinalMidiOutputDevice(CardinalBasePlugin* const plugin) - : fPlugin(plugin) {} + : fPlugin(plugin), + fQueueIndex(0) {} std::string getName() override { return "Cardinal"; } + void processMessages() + { + const MutexLocker cml(fQueueMutex); + + for (uint8_t i=0; iwriteMidiEvent(fQueue[i]); + + fQueueIndex = 0; + } + void sendMessage(const rack::midi::Message& message) override { - DISTRHO_SAFE_ASSERT_RETURN(fPlugin->isProcessing(),); - - if (message.bytes.size() > MidiEvent::kDataSize) + if (message.bytes.size() < 3) // FIXME + return; + if ((message.bytes[0] & 0xf0) == 0xf0) + return; + if (fQueueIndex == 128) return; - MidiEvent event; - event.frame = message.frame < 0 ? 0 : message.frame; + const MutexLocker cml(fQueueMutex); + + MidiEvent& event(fQueue[fQueueIndex++]); + event.frame = message.frame < 0 ? 0 : (message.frame - fPlugin->context->engine->getBlockFrame()); event.size = 3; // FIXME std::memcpy(event.data, message.bytes.data(), event.size); - fPlugin->writeMidiEvent(event); } }; @@ -285,9 +302,13 @@ struct CardinalMidiDriver : rack::midi::Driver CardinalBasePlugin* const plugin = reinterpret_cast(pluginContext->plugin); DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, nullptr); + if (! plugin->canAssignMidiOutputDevice()) + throw rack::Exception("Plugin driver only allows one midi output device to be used simultaneously"); + CardinalMidiOutputDevice* const device = new CardinalMidiOutputDevice(plugin); device->subscribe(output); + plugin->assignMidiOutputDevice(device); return device; } @@ -312,8 +333,17 @@ struct CardinalMidiDriver : rack::midi::Driver CardinalMidiOutputDevice* const device = reinterpret_cast(output->device); DISTRHO_SAFE_ASSERT_RETURN(device != nullptr,); - device->unsubscribe(output); - delete device; + CardinalPluginContext* const pluginContext = reinterpret_cast(output->context); + DISTRHO_SAFE_ASSERT_RETURN(pluginContext != nullptr,); + + CardinalBasePlugin* const plugin = reinterpret_cast(pluginContext->plugin); + DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); + + if (plugin->clearMidiOutputDevice(device)) + { + device->unsubscribe(output); + delete device; + } } };