Signed-off-by: falkTX <falktx@falktx.com>tags/22.02
@@ -311,8 +311,8 @@ class CardinalPlugin : public CardinalBasePlugin | |||||
// for base/context handling | // for base/context handling | ||||
bool fIsActive; | bool fIsActive; | ||||
CardinalAudioDevice* fCurrentAudioDevice; | CardinalAudioDevice* fCurrentAudioDevice; | ||||
CardinalMidiInputDevice* fCurrentMidiInput; | |||||
CardinalMidiOutputDevice* fCurrentMidiOutput; | |||||
CardinalMidiInputDevice** fCurrentMidiInputs; | |||||
CardinalMidiOutputDevice** fCurrentMidiOutputs; | |||||
uint64_t fPreviousFrame; | uint64_t fPreviousFrame; | ||||
Mutex fDeviceMutex; | Mutex fDeviceMutex; | ||||
@@ -327,8 +327,8 @@ public: | |||||
fAudioBufferOut(nullptr), | fAudioBufferOut(nullptr), | ||||
fIsActive(false), | fIsActive(false), | ||||
fCurrentAudioDevice(nullptr), | fCurrentAudioDevice(nullptr), | ||||
fCurrentMidiInput(nullptr), | |||||
fCurrentMidiOutput(nullptr), | |||||
fCurrentMidiInputs(nullptr), | |||||
fCurrentMidiOutputs(nullptr), | |||||
fPreviousFrame(0) | fPreviousFrame(0) | ||||
{ | { | ||||
fWindowParameters[kWindowParameterShowTooltips] = 1.0f; | fWindowParameters[kWindowParameterShowTooltips] = 1.0f; | ||||
@@ -397,19 +397,21 @@ public: | |||||
fInitializer->oscPlugin = nullptr; | fInitializer->oscPlugin = nullptr; | ||||
#endif | #endif | ||||
{ | |||||
const MutexLocker cml(fDeviceMutex); | |||||
fCurrentAudioDevice = nullptr; | |||||
fCurrentMidiInput = nullptr; | |||||
fCurrentMidiOutput = nullptr; | |||||
} | |||||
{ | { | ||||
const ScopedContext sc(this); | const ScopedContext sc(this); | ||||
context->patch->clear(); | context->patch->clear(); | ||||
delete context; | delete context; | ||||
} | } | ||||
{ | |||||
const MutexLocker cml(fDeviceMutex); | |||||
fCurrentAudioDevice = nullptr; | |||||
delete[] fCurrentMidiInputs; | |||||
fCurrentMidiInputs = nullptr; | |||||
delete[] fCurrentMidiOutputs; | |||||
fCurrentMidiOutputs = nullptr; | |||||
} | |||||
if (! fAutosavePath.empty()) | if (! fAutosavePath.empty()) | ||||
rack::system::removeRecursively(fAutosavePath); | rack::system::removeRecursively(fAutosavePath); | ||||
} | } | ||||
@@ -434,73 +436,115 @@ protected: | |||||
return fCurrentAudioDevice == nullptr; | 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); | 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); | 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 | 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; i<numDevs; ++i) | |||||
newDevs[i] = oldDevs[i]; | |||||
newDevs[numDevs+0] = dev; | |||||
newDevs[numDevs+1] = nullptr; | |||||
{ | |||||
const MutexLocker cml(fDeviceMutex); | |||||
fCurrentMidiInputs = newDevs; | |||||
} | |||||
delete[] oldDevs; | |||||
} | } | ||||
void assignMidiOutputDevice(CardinalMidiOutputDevice* const dev) noexcept override | void assignMidiOutputDevice(CardinalMidiOutputDevice* const dev) noexcept override | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fCurrentMidiOutput == nullptr,); | |||||
CardinalMidiOutputDevice** const oldDevs = fCurrentMidiOutputs; | |||||
const MutexLocker cml(fDeviceMutex); | |||||
fCurrentMidiOutput = dev; | |||||
} | |||||
uint numDevs = 0; | |||||
if (oldDevs != nullptr) | |||||
{ | |||||
while (oldDevs[numDevs] != nullptr) | |||||
++numDevs; | |||||
} | |||||
bool clearAudioDevice(CardinalAudioDevice* const dev) noexcept override | |||||
{ | |||||
const MutexLocker cml(fDeviceMutex); | |||||
CardinalMidiOutputDevice** const newDevs = new CardinalMidiOutputDevice*[numDevs + 2]; | |||||
if (fCurrentAudioDevice != dev) | |||||
return false; | |||||
for (uint i=0; i<numDevs; ++i) | |||||
newDevs[i] = oldDevs[i]; | |||||
fCurrentAudioDevice = nullptr; | |||||
return true; | |||||
newDevs[numDevs+0] = dev; | |||||
newDevs[numDevs+1] = nullptr; | |||||
{ | |||||
const MutexLocker cml(fDeviceMutex); | |||||
fCurrentMidiOutputs = newDevs; | |||||
} | |||||
delete[] oldDevs; | |||||
} | } | ||||
bool clearMidiInputDevice(CardinalMidiInputDevice* const dev) noexcept override | |||||
void clearMidiInputDevice(CardinalMidiInputDevice* const dev) noexcept override | |||||
{ | { | ||||
const MutexLocker cml(fDeviceMutex); | const MutexLocker cml(fDeviceMutex); | ||||
if (fCurrentMidiInput != dev) | |||||
return false; | |||||
CardinalMidiInputDevice** const inputs = fCurrentMidiInputs; | |||||
DISTRHO_SAFE_ASSERT_RETURN(inputs != nullptr,); | |||||
fCurrentMidiInput = nullptr; | |||||
return true; | |||||
for (uint i=0; inputs[i] != nullptr; ++i) | |||||
{ | |||||
CardinalMidiInputDevice* const input = inputs[i]; | |||||
if (input != dev) | |||||
continue; | |||||
for (; inputs[i+1] != nullptr; ++i) | |||||
inputs[i] = inputs[i+1]; | |||||
inputs[i] = nullptr; | |||||
break; | |||||
} | |||||
} | } | ||||
bool clearMidiOutputDevice(CardinalMidiOutputDevice* const dev) noexcept override | |||||
void clearMidiOutputDevice(CardinalMidiOutputDevice* const dev) noexcept override | |||||
{ | { | ||||
const MutexLocker cml(fDeviceMutex); | const MutexLocker cml(fDeviceMutex); | ||||
if (fCurrentMidiOutput != dev) | |||||
return false; | |||||
CardinalMidiOutputDevice** const outputs = fCurrentMidiOutputs; | |||||
DISTRHO_SAFE_ASSERT_RETURN(outputs != nullptr,); | |||||
fCurrentMidiOutput = nullptr; | |||||
return true; | |||||
for (uint i=0; outputs[i] != nullptr; ++i) | |||||
{ | |||||
CardinalMidiOutputDevice* const output = outputs[i]; | |||||
if (output != dev) | |||||
continue; | |||||
for (; outputs[i+1] != nullptr; ++i) | |||||
outputs[i] = outputs[i+1]; | |||||
outputs[i] = nullptr; | |||||
break; | |||||
} | |||||
} | } | ||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
@@ -858,8 +902,11 @@ protected: | |||||
fPreviousFrame = timePos.frame; | fPreviousFrame = timePos.frame; | ||||
} | } | ||||
if (fCurrentMidiInput != nullptr) | |||||
fCurrentMidiInput->handleMessagesFromHost(midiEvents, midiEventCount); | |||||
if (CardinalMidiInputDevice** inputs = fCurrentMidiInputs) | |||||
{ | |||||
for (;*inputs != nullptr; ++inputs) | |||||
(*inputs)->handleMessagesFromHost(midiEvents, midiEventCount); | |||||
} | |||||
if (fCurrentAudioDevice != nullptr) | if (fCurrentAudioDevice != nullptr) | ||||
{ | { | ||||
@@ -900,9 +947,6 @@ protected: | |||||
std::memset(outputs[0], 0, sizeof(float)*frames); | std::memset(outputs[0], 0, sizeof(float)*frames); | ||||
std::memset(outputs[1], 0, sizeof(float)*frames); | std::memset(outputs[1], 0, sizeof(float)*frames); | ||||
} | } | ||||
if (fCurrentMidiOutput != nullptr) | |||||
fCurrentMidiOutput->processMessages(); | |||||
} | } | ||||
void bufferSizeChanged(const uint32_t newBufferSize) override | void bufferSizeChanged(const uint32_t newBufferSize) override | ||||
@@ -117,14 +117,12 @@ public: | |||||
~CardinalBasePlugin() override {} | ~CardinalBasePlugin() override {} | ||||
virtual bool isActive() const noexcept = 0; | virtual bool isActive() const noexcept = 0; | ||||
virtual bool canAssignAudioDevice() 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 assignAudioDevice(CardinalAudioDevice* dev) noexcept = 0; | ||||
virtual void assignMidiInputDevice(CardinalMidiInputDevice* dev) noexcept = 0; | virtual void assignMidiInputDevice(CardinalMidiInputDevice* dev) noexcept = 0; | ||||
virtual void assignMidiOutputDevice(CardinalMidiOutputDevice* 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 | #ifndef HEADLESS | ||||
@@ -211,44 +211,70 @@ 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), | |||||
fQueueIndex(0) {} | |||||
: fPlugin(plugin) {} | |||||
std::string getName() override | std::string getName() override | ||||
{ | { | ||||
return "Cardinal"; | 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; i<fQueueIndex; ++i) | |||||
fPlugin->writeMidiEvent(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); | 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<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->canAssignMidiInputDevice()) | |||||
throw rack::Exception("Plugin driver only allows one midi input device to be used simultaneously"); | |||||
CardinalMidiInputDevice* const device = new CardinalMidiInputDevice(plugin); | CardinalMidiInputDevice* const device = new CardinalMidiInputDevice(plugin); | ||||
device->subscribe(input); | device->subscribe(input); | ||||
plugin->assignMidiInputDevice(device); | plugin->assignMidiInputDevice(device); | ||||
return device; | return device; | ||||
} | } | ||||
@@ -319,12 +341,8 @@ 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); | plugin->assignMidiOutputDevice(device); | ||||
return device; | return device; | ||||
} | } | ||||
@@ -340,11 +358,9 @@ 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,); | 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 | void unsubscribeOutput(int, rack::midi::Output* const output) override | ||||
@@ -358,11 +374,9 @@ 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,); | DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,); | ||||
if (plugin->clearMidiOutputDevice(device)) | |||||
{ | |||||
device->unsubscribe(output); | |||||
delete device; | |||||
} | |||||
plugin->clearMidiOutputDevice(device); | |||||
device->unsubscribe(output); | |||||
delete device; | |||||
} | } | ||||
}; | }; | ||||