Signed-off-by: falkTX <falktx@falktx.com>tags/22.02
| @@ -35,7 +35,6 @@ | |||||
| # undef DEBUG | # undef DEBUG | ||||
| #endif | #endif | ||||
| #include <atomic> | |||||
| #include <list> | #include <list> | ||||
| #include "DistrhoPluginUtils.hpp" | #include "DistrhoPluginUtils.hpp" | ||||
| @@ -176,11 +175,10 @@ class CardinalPlugin : public CardinalBasePlugin | |||||
| // for base/context handling | // for base/context handling | ||||
| bool fIsActive; | bool fIsActive; | ||||
| std::atomic<bool> fIsProcessing; | |||||
| rack::audio::Device* fCurrentDevice; | |||||
| Mutex fDeviceMutex; | |||||
| CardinalAudioDevice* fCurrentAudioDevice; | |||||
| CardinalMidiOutputDevice* fCurrentMidiOutput; | |||||
| std::list<CardinalMidiInputDevice*> fMidiInputs; | std::list<CardinalMidiInputDevice*> fMidiInputs; | ||||
| volatile pthread_t fProcessThread; | |||||
| Mutex fDeviceMutex; | |||||
| float fWindowParameters[kWindowParameterCount]; | float fWindowParameters[kWindowParameterCount]; | ||||
| @@ -191,13 +189,8 @@ public: | |||||
| fAudioBufferIn(nullptr), | fAudioBufferIn(nullptr), | ||||
| fAudioBufferOut(nullptr), | fAudioBufferOut(nullptr), | ||||
| fIsActive(false), | 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[kWindowParameterCableOpacity] = 50.0f; | ||||
| fWindowParameters[kWindowParameterCableTension] = 50.0f; | fWindowParameters[kWindowParameterCableTension] = 50.0f; | ||||
| @@ -275,38 +268,59 @@ protected: | |||||
| return fIsActive; | return fIsActive; | ||||
| } | } | ||||
| bool isProcessing() const noexcept override | |||||
| bool canAssignAudioDevice() const noexcept override | |||||
| { | { | ||||
| return fIsProcessing.load() && pthread_equal(fProcessThread, pthread_self() != 0); | |||||
| const MutexLocker cml(fDeviceMutex); | |||||
| return fCurrentAudioDevice == nullptr; | |||||
| } | } | ||||
| bool canAssignDevice() const noexcept override | |||||
| bool canAssignMidiOutputDevice() const noexcept override | |||||
| { | { | ||||
| const MutexLocker cml(fDeviceMutex); | const MutexLocker cml(fDeviceMutex); | ||||
| return fCurrentDevice == nullptr; | |||||
| return fCurrentMidiOutput == nullptr; | |||||
| } | } | ||||
| void assignDevice(rack::audio::Device* const dev) noexcept override | |||||
| void assignAudioDevice(CardinalAudioDevice* const dev) noexcept override | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fCurrentDevice == nullptr,); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fCurrentAudioDevice == nullptr,); | |||||
| const MutexLocker cml(fDeviceMutex); | 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); | const MutexLocker cml(fDeviceMutex); | ||||
| fCurrentMidiOutput = dev; | |||||
| } | |||||
| if (fCurrentDevice != dev) | |||||
| bool clearAudioDevice(CardinalAudioDevice* const dev) noexcept override | |||||
| { | |||||
| const MutexLocker cml(fDeviceMutex); | |||||
| if (fCurrentAudioDevice != dev) | |||||
| return false; | 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; | return true; | ||||
| } | } | ||||
| void addMidiInput(CardinalMidiInputDevice* const dev) override | void addMidiInput(CardinalMidiInputDevice* const dev) override | ||||
| { | { | ||||
| // NOTE this will xrun | |||||
| const MutexLocker cml(fDeviceMutex); | const MutexLocker cml(fDeviceMutex); | ||||
| fMidiInputs.push_back(dev); | fMidiInputs.push_back(dev); | ||||
| @@ -314,8 +328,10 @@ protected: | |||||
| void removeMidiInput(CardinalMidiInputDevice* const dev) override | void removeMidiInput(CardinalMidiInputDevice* const dev) override | ||||
| { | { | ||||
| // NOTE this will xrun | |||||
| const MutexLocker cml(fDeviceMutex); | const MutexLocker cml(fDeviceMutex); | ||||
| fMidiInputs.remove(dev); | |||||
| } | } | ||||
| /* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
| @@ -512,8 +528,8 @@ protected: | |||||
| { | { | ||||
| const MutexLocker cml(fDeviceMutex); | const MutexLocker cml(fDeviceMutex); | ||||
| if (fCurrentDevice != nullptr) | |||||
| fCurrentDevice->onStartStream(); | |||||
| if (fCurrentAudioDevice != nullptr) | |||||
| fCurrentAudioDevice->onStartStream(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -522,8 +538,8 @@ protected: | |||||
| { | { | ||||
| const MutexLocker cml(fDeviceMutex); | const MutexLocker cml(fDeviceMutex); | ||||
| if (fCurrentDevice != nullptr) | |||||
| fCurrentDevice->onStopStream(); | |||||
| if (fCurrentAudioDevice != nullptr) | |||||
| fCurrentAudioDevice->onStopStream(); | |||||
| } | } | ||||
| delete[] fAudioBufferIn; | delete[] fAudioBufferIn; | ||||
| @@ -539,34 +555,33 @@ protected: | |||||
| context->engine->stepBlock(frames); | context->engine->stepBlock(frames); | ||||
| */ | */ | ||||
| fProcessThread = pthread_self(); | |||||
| const MutexLocker cml(fDeviceMutex); | const MutexLocker cml(fDeviceMutex); | ||||
| // const MutexTryLocker cmtl(fPatchMutex); | |||||
| if (fCurrentDevice == nullptr /*|| cmtl.wasNotLocked()*/) | |||||
| if (fCurrentAudioDevice != nullptr) | |||||
| { | { | ||||
| std::memset(outputs[0], 0, sizeof(float)*frames); | |||||
| std::memset(outputs[1], 0, sizeof(float)*frames); | |||||
| return; | |||||
| for (uint32_t i=0, j=0; i<frames; ++i) | |||||
| { | |||||
| fAudioBufferIn[j++] = inputs[0][i]; | |||||
| fAudioBufferIn[j++] = inputs[1][i]; | |||||
| } | |||||
| } | } | ||||
| for (uint32_t i=0, j=0; i<frames; ++i) | |||||
| else | |||||
| { | { | ||||
| fAudioBufferIn[j++] = inputs[0][i]; | |||||
| fAudioBufferIn[j++] = inputs[1][i]; | |||||
| std::memset(outputs[0], 0, sizeof(float)*frames); | |||||
| std::memset(outputs[1], 0, sizeof(float)*frames); | |||||
| } | } | ||||
| std::memset(fAudioBufferOut, 0, sizeof(float)*frames*DISTRHO_PLUGIN_NUM_OUTPUTS); | std::memset(fAudioBufferOut, 0, sizeof(float)*frames*DISTRHO_PLUGIN_NUM_OUTPUTS); | ||||
| fIsProcessing.store(1); | |||||
| for (CardinalMidiInputDevice* dev : fMidiInputs) | for (CardinalMidiInputDevice* dev : fMidiInputs) | ||||
| dev->handleMessagesFromHost(midiEvents, midiEventCount); | dev->handleMessagesFromHost(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<frames; ++i) | for (uint32_t i=0, j=0; i<frames; ++i) | ||||
| { | { | ||||
| @@ -55,6 +55,7 @@ struct CardinalPluginContext : rack::Context { | |||||
| // ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
| struct CardinalAudioDevice; | |||||
| struct CardinalMidiInputDevice; | struct CardinalMidiInputDevice; | ||||
| struct CardinalMidiOutputDevice; | struct CardinalMidiOutputDevice; | ||||
| @@ -67,10 +68,12 @@ public: | |||||
| context(new CardinalPluginContext(this)) {} | context(new CardinalPluginContext(this)) {} | ||||
| ~CardinalBasePlugin() override {} | ~CardinalBasePlugin() override {} | ||||
| virtual bool isActive() const noexcept = 0; | 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 bool canAssignAudioDevice() const noexcept = 0; | |||||
| virtual bool canAssignMidiOutputDevice() const noexcept = 0; | |||||
| virtual void assignAudioDevice(CardinalAudioDevice* dev) noexcept = 0; | |||||
| virtual void assignMidiOutputDevice(CardinalMidiOutputDevice* dev) noexcept = 0; | |||||
| virtual bool clearAudioDevice(CardinalAudioDevice* dev) noexcept = 0; | |||||
| virtual bool clearMidiOutputDevice(CardinalMidiOutputDevice* dev) noexcept = 0; | |||||
| virtual void addMidiInput(CardinalMidiInputDevice* dev) = 0; | virtual void addMidiInput(CardinalMidiInputDevice* dev) = 0; | ||||
| virtual void removeMidiInput(CardinalMidiInputDevice* dev) = 0; | virtual void removeMidiInput(CardinalMidiInputDevice* dev) = 0; | ||||
| @@ -113,7 +113,7 @@ struct CardinalAudioDriver : rack::audio::Driver | |||||
| CardinalBasePlugin* const plugin = reinterpret_cast<CardinalBasePlugin*>(pluginContext->plugin); | CardinalBasePlugin* const plugin = reinterpret_cast<CardinalBasePlugin*>(pluginContext->plugin); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, nullptr); | 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"); | throw rack::Exception("Plugin driver only allows one audio device to be used simultaneously"); | ||||
| CardinalAudioDevice* const device = new CardinalAudioDevice(plugin); | CardinalAudioDevice* const device = new CardinalAudioDevice(plugin); | ||||
| @@ -122,7 +122,7 @@ struct CardinalAudioDriver : rack::audio::Driver | |||||
| if (plugin->isActive()) | if (plugin->isActive()) | ||||
| device->onStartStream(); | device->onStartStream(); | ||||
| plugin->assignDevice(device); | |||||
| plugin->assignAudioDevice(device); | |||||
| return device; | return device; | ||||
| } | } | ||||
| @@ -137,7 +137,7 @@ struct CardinalAudioDriver : rack::audio::Driver | |||||
| CardinalBasePlugin* const plugin = reinterpret_cast<CardinalBasePlugin*>(pluginContext->plugin); | CardinalBasePlugin* const plugin = reinterpret_cast<CardinalBasePlugin*>(pluginContext->plugin); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); | ||||
| if (plugin->clearDevice(device)) | |||||
| if (plugin->clearAudioDevice(device)) | |||||
| { | { | ||||
| device->onStopStream(); | device->onStopStream(); | ||||
| device->unsubscribe(port); | device->unsubscribe(port); | ||||
| @@ -197,27 +197,44 @@ struct CardinalMidiInputDevice : rack::midi::InputDevice | |||||
| struct CardinalMidiOutputDevice : rack::midi::OutputDevice | struct CardinalMidiOutputDevice : rack::midi::OutputDevice | ||||
| { | { | ||||
| CardinalBasePlugin* const fPlugin; | CardinalBasePlugin* const fPlugin; | ||||
| MidiEvent fQueue[128]; | |||||
| Mutex fQueueMutex; | |||||
| uint8_t fQueueIndex; | |||||
| CardinalMidiOutputDevice(CardinalBasePlugin* const plugin) | CardinalMidiOutputDevice(CardinalBasePlugin* const plugin) | ||||
| : fPlugin(plugin) {} | |||||
| : fPlugin(plugin), | |||||
| fQueueIndex(0) {} | |||||
| std::string getName() override | std::string getName() override | ||||
| { | { | ||||
| return "Cardinal"; | return "Cardinal"; | ||||
| } | } | ||||
| void sendMessage(const rack::midi::Message& message) override | |||||
| void processMessages() | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fPlugin->isProcessing(),); | |||||
| const MutexLocker cml(fQueueMutex); | |||||
| for (uint8_t i=0; i<fQueueIndex; ++i) | |||||
| fPlugin->writeMidiEvent(fQueue[i]); | |||||
| if (message.bytes.size() > MidiEvent::kDataSize) | |||||
| fQueueIndex = 0; | |||||
| } | |||||
| 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; | 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 | event.size = 3; // FIXME | ||||
| std::memcpy(event.data, message.bytes.data(), event.size); | 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<CardinalBasePlugin*>(pluginContext->plugin); | CardinalBasePlugin* const plugin = reinterpret_cast<CardinalBasePlugin*>(pluginContext->plugin); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, nullptr); | 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); | CardinalMidiOutputDevice* const device = new CardinalMidiOutputDevice(plugin); | ||||
| device->subscribe(output); | device->subscribe(output); | ||||
| plugin->assignMidiOutputDevice(device); | |||||
| return device; | return device; | ||||
| } | } | ||||
| @@ -312,8 +333,17 @@ struct CardinalMidiDriver : rack::midi::Driver | |||||
| CardinalMidiOutputDevice* const device = reinterpret_cast<CardinalMidiOutputDevice*>(output->device); | CardinalMidiOutputDevice* const device = reinterpret_cast<CardinalMidiOutputDevice*>(output->device); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(device != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(device != nullptr,); | ||||
| device->unsubscribe(output); | |||||
| delete device; | |||||
| CardinalPluginContext* const pluginContext = reinterpret_cast<CardinalPluginContext*>(output->context); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(pluginContext != nullptr,); | |||||
| CardinalBasePlugin* const plugin = reinterpret_cast<CardinalBasePlugin*>(pluginContext->plugin); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); | |||||
| if (plugin->clearMidiOutputDevice(device)) | |||||
| { | |||||
| device->unsubscribe(output); | |||||
| delete device; | |||||
| } | |||||
| } | } | ||||
| }; | }; | ||||