diff --git a/src/CardinalPlugin.cpp b/src/CardinalPlugin.cpp index ee1d5b3..3840b59 100644 --- a/src/CardinalPlugin.cpp +++ b/src/CardinalPlugin.cpp @@ -311,8 +311,8 @@ class CardinalPlugin : public CardinalBasePlugin // for base/context handling bool fIsActive; CardinalAudioDevice* fCurrentAudioDevice; - CardinalMidiInputDevice* fCurrentMidiInput; - CardinalMidiOutputDevice* fCurrentMidiOutput; + CardinalMidiInputDevice** fCurrentMidiInputs; + CardinalMidiOutputDevice** fCurrentMidiOutputs; uint64_t fPreviousFrame; Mutex fDeviceMutex; @@ -327,8 +327,8 @@ public: fAudioBufferOut(nullptr), fIsActive(false), fCurrentAudioDevice(nullptr), - fCurrentMidiInput(nullptr), - fCurrentMidiOutput(nullptr), + fCurrentMidiInputs(nullptr), + fCurrentMidiOutputs(nullptr), fPreviousFrame(0) { fWindowParameters[kWindowParameterShowTooltips] = 1.0f; @@ -397,19 +397,21 @@ public: fInitializer->oscPlugin = nullptr; #endif - { - const MutexLocker cml(fDeviceMutex); - fCurrentAudioDevice = nullptr; - fCurrentMidiInput = nullptr; - fCurrentMidiOutput = nullptr; - } - { const ScopedContext sc(this); context->patch->clear(); delete context; } + { + const MutexLocker cml(fDeviceMutex); + fCurrentAudioDevice = nullptr; + delete[] fCurrentMidiInputs; + fCurrentMidiInputs = nullptr; + delete[] fCurrentMidiOutputs; + fCurrentMidiOutputs = nullptr; + } + if (! fAutosavePath.empty()) rack::system::removeRecursively(fAutosavePath); } @@ -434,73 +436,115 @@ protected: return fCurrentAudioDevice == nullptr; } - bool canAssignMidiInputDevice() const noexcept override + void assignAudioDevice(CardinalAudioDevice* const dev) noexcept override { + DISTRHO_SAFE_ASSERT_RETURN(fCurrentAudioDevice == nullptr,); + const MutexLocker cml(fDeviceMutex); - return fCurrentMidiInput == nullptr; + fCurrentAudioDevice = dev; } - bool canAssignMidiOutputDevice() const noexcept override + bool clearAudioDevice(CardinalAudioDevice* const dev) noexcept override { const MutexLocker cml(fDeviceMutex); - return fCurrentMidiOutput == nullptr; - } - void assignAudioDevice(CardinalAudioDevice* const dev) noexcept override - { - DISTRHO_SAFE_ASSERT_RETURN(fCurrentAudioDevice == nullptr,); + if (fCurrentAudioDevice != dev) + return false; - const MutexLocker cml(fDeviceMutex); - fCurrentAudioDevice = dev; + fCurrentAudioDevice = nullptr; + return true; } void assignMidiInputDevice(CardinalMidiInputDevice* const dev) noexcept override { - DISTRHO_SAFE_ASSERT_RETURN(fCurrentMidiInput == nullptr,); + CardinalMidiInputDevice** const oldDevs = fCurrentMidiInputs; - const MutexLocker cml(fDeviceMutex); - fCurrentMidiInput = dev; + uint numDevs = 0; + if (oldDevs != nullptr) + { + while (oldDevs[numDevs] != nullptr) + ++numDevs; + } + + CardinalMidiInputDevice** const newDevs = new CardinalMidiInputDevice*[numDevs + 2]; + + for (uint i=0; ihandleMessagesFromHost(midiEvents, midiEventCount); + if (CardinalMidiInputDevice** inputs = fCurrentMidiInputs) + { + for (;*inputs != nullptr; ++inputs) + (*inputs)->handleMessagesFromHost(midiEvents, midiEventCount); + } if (fCurrentAudioDevice != nullptr) { @@ -900,9 +947,6 @@ protected: std::memset(outputs[0], 0, sizeof(float)*frames); std::memset(outputs[1], 0, sizeof(float)*frames); } - - if (fCurrentMidiOutput != nullptr) - fCurrentMidiOutput->processMessages(); } void bufferSizeChanged(const uint32_t newBufferSize) override diff --git a/src/PluginContext.hpp b/src/PluginContext.hpp index 4898c09..f7cc916 100644 --- a/src/PluginContext.hpp +++ b/src/PluginContext.hpp @@ -117,14 +117,12 @@ public: ~CardinalBasePlugin() override {} virtual bool isActive() const noexcept = 0; virtual bool canAssignAudioDevice() const noexcept = 0; - virtual bool canAssignMidiInputDevice() const noexcept = 0; - virtual bool canAssignMidiOutputDevice() const noexcept = 0; + virtual bool clearAudioDevice(CardinalAudioDevice* dev) noexcept = 0; virtual void assignAudioDevice(CardinalAudioDevice* dev) noexcept = 0; virtual void assignMidiInputDevice(CardinalMidiInputDevice* dev) noexcept = 0; virtual void assignMidiOutputDevice(CardinalMidiOutputDevice* dev) noexcept = 0; - virtual bool clearAudioDevice(CardinalAudioDevice* dev) noexcept = 0; - virtual bool clearMidiInputDevice(CardinalMidiInputDevice* dev) noexcept = 0; - virtual bool clearMidiOutputDevice(CardinalMidiOutputDevice* dev) noexcept = 0; + virtual void clearMidiInputDevice(CardinalMidiInputDevice* dev) noexcept = 0; + virtual void clearMidiOutputDevice(CardinalMidiOutputDevice* dev) noexcept = 0; }; #ifndef HEADLESS diff --git a/src/PluginDriver.hpp b/src/PluginDriver.hpp index 52ddebc..7b7ed5d 100644 --- a/src/PluginDriver.hpp +++ b/src/PluginDriver.hpp @@ -211,44 +211,70 @@ 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), - fQueueIndex(0) {} + : fPlugin(plugin) {} std::string getName() override { return "Cardinal"; } - void processMessages() + void sendMessage(const rack::midi::Message& message) override { - const MutexLocker cml(fQueueMutex); + const size_t size = message.bytes.size(); + DISTRHO_SAFE_ASSERT_RETURN(size > 0,); - for (uint8_t i=0; iwriteMidiEvent(fQueue[i]); - - fQueueIndex = 0; - } + MidiEvent event; + event.frame = message.frame < 0 ? 0 : (message.frame - fPlugin->context->engine->getBlockFrame()); - void sendMessage(const rack::midi::Message& message) override - { - if (message.bytes.size() < 3) // FIXME - return; - if ((message.bytes[0] & 0xf0) == 0xf0) - return; - if (fQueueIndex == 128) - return; + switch (message.bytes[0] & 0xF0) + { + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + case 0xE0: + event.size = 3; + break; + case 0xC0: + case 0xD0: + event.size = 2; + break; + case 0xF0: + switch (message.bytes[0] & 0x0F) + { + case 0x0: + case 0x4: + case 0x5: + case 0x7: + case 0x9: + case 0xD: + // unsupported + return; + case 0x1: + case 0x2: + case 0x3: + case 0xE: + event.size = 3; + break; + case 0x6: + case 0x8: + case 0xA: + case 0xB: + case 0xC: + case 0xF: + event.size = 1; + break; + } + break; + } - const MutexLocker cml(fQueueMutex); + DISTRHO_SAFE_ASSERT_RETURN(size >= event.size,); - 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); } }; @@ -301,12 +327,8 @@ struct CardinalMidiDriver : rack::midi::Driver CardinalBasePlugin* const plugin = reinterpret_cast(pluginContext->plugin); DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, nullptr); - if (! plugin->canAssignMidiInputDevice()) - throw rack::Exception("Plugin driver only allows one midi input device to be used simultaneously"); - CardinalMidiInputDevice* const device = new CardinalMidiInputDevice(plugin); device->subscribe(input); - plugin->assignMidiInputDevice(device); return device; } @@ -319,12 +341,8 @@ 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; } @@ -340,11 +358,9 @@ struct CardinalMidiDriver : rack::midi::Driver CardinalBasePlugin* const plugin = reinterpret_cast(pluginContext->plugin); DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); - if (plugin->clearMidiInputDevice(device)) - { - device->unsubscribe(input); - delete device; - } + plugin->clearMidiInputDevice(device); + device->unsubscribe(input); + delete device; } void unsubscribeOutput(int, rack::midi::Output* const output) override @@ -358,11 +374,9 @@ struct CardinalMidiDriver : rack::midi::Driver CardinalBasePlugin* const plugin = reinterpret_cast(pluginContext->plugin); DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); - if (plugin->clearMidiOutputDevice(device)) - { - device->unsubscribe(output); - delete device; - } + plugin->clearMidiOutputDevice(device); + device->unsubscribe(output); + delete device; } };