Override Engine to 100% ensure proper threading (ie, none)

Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
falkTX 2021-11-03 20:34:41 +00:00
parent 9ee6524004
commit 3766f0bd42
No known key found for this signature in database
GPG key ID: CDBAA37ABC74FBA0
5 changed files with 1177 additions and 81 deletions

View file

@ -314,8 +314,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; CardinalMidiOutputDevice* fCurrentMidiOutput;
std::list<CardinalMidiInputDevice*> fMidiInputs;
uint64_t fPreviousFrame; uint64_t fPreviousFrame;
Mutex fDeviceMutex; Mutex fDeviceMutex;
@ -332,6 +332,7 @@ public:
fAudioBufferOut(nullptr), fAudioBufferOut(nullptr),
fIsActive(false), fIsActive(false),
fCurrentAudioDevice(nullptr), fCurrentAudioDevice(nullptr),
fCurrentMidiInput(nullptr),
fCurrentMidiOutput(nullptr), fCurrentMidiOutput(nullptr),
fPreviousFrame(0) fPreviousFrame(0)
{ {
@ -364,9 +365,17 @@ public:
} }
} DISTRHO_SAFE_EXCEPTION("create unique temporary path"); } DISTRHO_SAFE_EXCEPTION("create unique temporary path");
const float sampleRate = getSampleRate();
rack::settings::sampleRate = sampleRate;
context->bufferSize = getBufferSize();
context->sampleRate = sampleRate;
const ScopedContext sc(this); const ScopedContext sc(this);
context->engine = new rack::engine::Engine; context->engine = new rack::engine::Engine;
context->engine->setSampleRate(sampleRate);
context->history = new rack::history::State; context->history = new rack::history::State;
context->patch = new rack::patch::Manager; context->patch = new rack::patch::Manager;
context->patch->autosavePath = fAutosavePath; context->patch->autosavePath = fAutosavePath;
@ -375,9 +384,9 @@ public:
context->event = new rack::widget::EventState; context->event = new rack::widget::EventState;
context->scene = new rack::app::Scene; context->scene = new rack::app::Scene;
context->event->rootWidget = context->scene; context->event->rootWidget = context->scene;
context->patch->loadTemplate(); context->patch->loadTemplate();
context->scene->rackScroll->reset(); context->scene->rackScroll->reset();
context->engine->startFallbackThread();
#ifdef HAVE_LIBLO #ifdef HAVE_LIBLO
fInitializer->oscPlugin = this; fInitializer->oscPlugin = this;
@ -400,13 +409,22 @@ public:
fInitializer->oscPlugin = nullptr; fInitializer->oscPlugin = nullptr;
#endif #endif
rack::contextSet(context); {
const MutexLocker cml(fDeviceMutex);
fCurrentAudioDevice = nullptr;
fCurrentMidiInput = nullptr;
fCurrentMidiOutput = nullptr;
}
{
const ScopedContext sc(this);
#if defined(__MOD_DEVICES__) && !defined(HEADLESS) #if defined(__MOD_DEVICES__) && !defined(HEADLESS)
delete context->window; delete context->window;
context->window = nullptr; context->window = nullptr;
#endif #endif
delete context; delete context;
rack::contextSet(nullptr); }
if (! fAutosavePath.empty()) if (! fAutosavePath.empty())
rack::system::removeRecursively(fAutosavePath); rack::system::removeRecursively(fAutosavePath);
@ -432,6 +450,12 @@ protected:
return fCurrentAudioDevice == nullptr; return fCurrentAudioDevice == nullptr;
} }
bool canAssignMidiInputDevice() const noexcept override
{
const MutexLocker cml(fDeviceMutex);
return fCurrentMidiInput == nullptr;
}
bool canAssignMidiOutputDevice() const noexcept override bool canAssignMidiOutputDevice() const noexcept override
{ {
const MutexLocker cml(fDeviceMutex); const MutexLocker cml(fDeviceMutex);
@ -446,6 +470,14 @@ protected:
fCurrentAudioDevice = dev; fCurrentAudioDevice = dev;
} }
void assignMidiInputDevice(CardinalMidiInputDevice* const dev) noexcept override
{
DISTRHO_SAFE_ASSERT_RETURN(fCurrentMidiInput == nullptr,);
const MutexLocker cml(fDeviceMutex);
fCurrentMidiInput = dev;
}
void assignMidiOutputDevice(CardinalMidiOutputDevice* const dev) noexcept override void assignMidiOutputDevice(CardinalMidiOutputDevice* const dev) noexcept override
{ {
DISTRHO_SAFE_ASSERT_RETURN(fCurrentMidiOutput == nullptr,); DISTRHO_SAFE_ASSERT_RETURN(fCurrentMidiOutput == nullptr,);
@ -465,6 +497,17 @@ protected:
return true; return true;
} }
bool clearMidiInputDevice(CardinalMidiInputDevice* const dev) noexcept override
{
const MutexLocker cml(fDeviceMutex);
if (fCurrentMidiInput != dev)
return false;
fCurrentMidiInput = nullptr;
return true;
}
bool clearMidiOutputDevice(CardinalMidiOutputDevice* const dev) noexcept override bool clearMidiOutputDevice(CardinalMidiOutputDevice* const dev) noexcept override
{ {
const MutexLocker cml(fDeviceMutex); const MutexLocker cml(fDeviceMutex);
@ -476,22 +519,6 @@ protected:
return true; return true;
} }
void addMidiInput(CardinalMidiInputDevice* const dev) override
{
// NOTE this will xrun
const MutexLocker cml(fDeviceMutex);
fMidiInputs.push_back(dev);
}
void removeMidiInput(CardinalMidiInputDevice* const dev) override
{
// NOTE this will xrun
const MutexLocker cml(fDeviceMutex);
fMidiInputs.remove(dev);
}
/* -------------------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------------------
* Information */ * Information */
@ -746,7 +773,10 @@ protected:
rack::system::createDirectories(fAutosavePath); rack::system::createDirectories(fAutosavePath);
rack::system::unarchiveToDirectory(data, fAutosavePath); rack::system::unarchiveToDirectory(data, fAutosavePath);
try {
context->patch->loadAutosave(); context->patch->loadAutosave();
} DISTRHO_SAFE_EXCEPTION_RETURN("setState loadAutosave",);
// context->history->setSaved(); // context->history->setSaved();
} }
@ -798,28 +828,8 @@ protected:
void run(const float** const inputs, float** const outputs, const uint32_t frames, void run(const float** const inputs, float** const outputs, const uint32_t frames,
const MidiEvent* const midiEvents, const uint32_t midiEventCount) override const MidiEvent* const midiEvents, const uint32_t midiEventCount) override
{ {
/*
context->engine->setFrame(getTimePosition().frame);
context->engine->stepBlock(frames);
*/
const MutexLocker cml(fDeviceMutex); const MutexLocker cml(fDeviceMutex);
rack::contextSet(context);
if (fCurrentAudioDevice != nullptr)
{
#if DISTRHO_PLUGIN_NUM_INPUTS != 0
for (uint32_t i=0, j=0; i<frames; ++i)
{
fAudioBufferIn[j++] = inputs[0][i];
fAudioBufferIn[j++] = inputs[1][i];
}
#endif
}
else
{
std::memset(outputs[0], 0, sizeof(float)*frames);
std::memset(outputs[1], 0, sizeof(float)*frames);
}
{ {
const TimePosition& timePos(getTimePosition()); const TimePosition& timePos(getTimePosition());
@ -846,24 +856,27 @@ protected:
fPreviousFrame = timePos.frame; fPreviousFrame = timePos.frame;
} }
std::memset(fAudioBufferOut, 0, sizeof(float)*frames*DISTRHO_PLUGIN_NUM_OUTPUTS); if (fCurrentMidiInput != nullptr)
fCurrentMidiInput->handleMessagesFromHost(midiEvents, midiEventCount);
for (CardinalMidiInputDevice* dev : fMidiInputs)
dev->handleMessagesFromHost(midiEvents, midiEventCount);
if (fCurrentAudioDevice != nullptr) if (fCurrentAudioDevice != nullptr)
{ {
#if DISTRHO_PLUGIN_NUM_INPUTS == 0 #if DISTRHO_PLUGIN_NUM_INPUTS != 0
const float* const insPtr = nullptr; for (uint32_t i=0, j=0; i<frames; ++i)
#else {
const float* const insPtr = fAudioBufferIn; fAudioBufferIn[j++] = inputs[0][i];
fAudioBufferIn[j++] = inputs[1][i];
}
fCurrentAudioDevice->processInput(fAudioBufferIn, DISTRHO_PLUGIN_NUM_INPUTS, frames);
#endif #endif
fCurrentAudioDevice->processBuffer(insPtr, DISTRHO_PLUGIN_NUM_INPUTS,
fAudioBufferOut, DISTRHO_PLUGIN_NUM_OUTPUTS, frames);
} }
if (fCurrentMidiOutput != nullptr) context->engine->stepBlock(frames);
fCurrentMidiOutput->processMessages();
if (fCurrentAudioDevice != nullptr)
{
std::memset(fAudioBufferOut, 0, sizeof(float)*frames*DISTRHO_PLUGIN_NUM_OUTPUTS);
fCurrentAudioDevice->processOutput(fAudioBufferOut, DISTRHO_PLUGIN_NUM_OUTPUTS, frames);
for (uint32_t i=0, j=0; i<frames; ++i) for (uint32_t i=0, j=0; i<frames; ++i)
{ {
@ -871,11 +884,27 @@ protected:
outputs[1][i] = fAudioBufferOut[j++]; outputs[1][i] = fAudioBufferOut[j++];
} }
} }
else
{
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
{
rack::contextSet(context);
context->bufferSize = newBufferSize;
}
void sampleRateChanged(const double newSampleRate) override void sampleRateChanged(const double newSampleRate) override
{ {
rack::contextSet(context); rack::contextSet(context);
rack::settings::sampleRate = newSampleRate; rack::settings::sampleRate = newSampleRate;
context->sampleRate = newSampleRate;
context->engine->setSampleRate(newSampleRate); context->engine->setSampleRate(newSampleRate);
} }

View file

@ -71,6 +71,7 @@ BUILD_C_FLAGS += -std=gnu11
# Rack files to build # Rack files to build
RACK_FILES += AsyncDialog.cpp RACK_FILES += AsyncDialog.cpp
RACK_FILES += override/Engine.cpp
RACK_FILES += override/asset.cpp RACK_FILES += override/asset.cpp
RACK_FILES += override/context.cpp RACK_FILES += override/context.cpp
RACK_FILES += override/dep.cpp RACK_FILES += override/dep.cpp
@ -95,6 +96,7 @@ IGNORED_FILES += Rack/src/network.cpp
IGNORED_FILES += Rack/src/rtaudio.cpp IGNORED_FILES += Rack/src/rtaudio.cpp
IGNORED_FILES += Rack/src/rtmidi.cpp IGNORED_FILES += Rack/src/rtmidi.cpp
IGNORED_FILES += Rack/src/app/MenuBar.cpp IGNORED_FILES += Rack/src/app/MenuBar.cpp
IGNORED_FILES += Rack/src/engine/Engine.cpp
IGNORED_FILES += Rack/src/window/Window.cpp IGNORED_FILES += Rack/src/window/Window.cpp
RACK_FILES += $(wildcard Rack/src/*.c) RACK_FILES += $(wildcard Rack/src/*.c)

View file

@ -80,25 +80,14 @@ 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 canAssignMidiOutputDevice() const 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 assignMidiOutputDevice(CardinalMidiOutputDevice* dev) noexcept = 0; virtual void assignMidiOutputDevice(CardinalMidiOutputDevice* dev) noexcept = 0;
virtual bool clearAudioDevice(CardinalAudioDevice* 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 bool clearMidiOutputDevice(CardinalMidiOutputDevice* dev) noexcept = 0;
virtual void addMidiInput(CardinalMidiInputDevice* dev) = 0;
virtual void removeMidiInput(CardinalMidiInputDevice* dev) = 0;
protected:
void bufferSizeChanged(const uint32_t newBufferSize) override
{
context->bufferSize = newBufferSize;
}
void sampleRateChanged(const double newSampleRate) override
{
context->sampleRate = newSampleRate;
// context->engine->setSampleRate(newSampleRate);
}
}; };
// ----------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------

View file

@ -67,6 +67,18 @@ struct CardinalAudioDevice : rack::audio::Device
void setBlockSize(int) override {} void setBlockSize(int) override {}
void setSampleRate(float) override {} void setSampleRate(float) override {}
void processInput(const float* const input, const int inputStride, const int frames)
{
for (rack::audio::Port* port : subscribed)
port->processInput(input + port->inputOffset, inputStride, frames);
}
void processOutput(float* const output, const int outputStride, const int frames)
{
for (rack::audio::Port* port : subscribed)
port->processOutput(output + port->outputOffset, outputStride, frames);
}
}; };
// ----------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------
@ -139,7 +151,9 @@ struct CardinalAudioDriver : rack::audio::Driver
if (plugin->clearAudioDevice(device)) if (plugin->clearAudioDevice(device))
{ {
if (plugin->isActive())
device->onStopStream(); device->onStopStream();
device->unsubscribe(port); device->unsubscribe(port);
delete device; delete device;
} }
@ -156,7 +170,7 @@ struct CardinalMidiInputDevice : rack::midi::InputDevice
CardinalMidiInputDevice(CardinalBasePlugin* const plugin) CardinalMidiInputDevice(CardinalBasePlugin* const plugin)
: fPlugin(plugin) : fPlugin(plugin)
{ {
msg.bytes.reserve(0xff); msg.bytes.resize(0xff);
} }
std::string getName() override std::string getName() override
@ -177,7 +191,7 @@ struct CardinalMidiInputDevice : rack::midi::InputDevice
if (midiEvent.size > MidiEvent::kDataSize) if (midiEvent.size > MidiEvent::kDataSize)
{ {
data = midiEvent.dataExt; data = midiEvent.dataExt;
msg.bytes.reserve(midiEvent.size); msg.bytes.resize(midiEvent.size);
} }
else else
{ {
@ -287,10 +301,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->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->addMidiInput(device); plugin->assignMidiInputDevice(device);
return device; return device;
} }
@ -323,10 +340,12 @@ 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,);
plugin->removeMidiInput(device); if (plugin->clearMidiInputDevice(device))
{
device->unsubscribe(input); device->unsubscribe(input);
delete device; delete device;
} }
}
void unsubscribeOutput(int, rack::midi::Output* const output) override void unsubscribeOutput(int, rack::midi::Output* const output) override
{ {

1057
src/override/Engine.cpp Normal file

File diff suppressed because it is too large Load diff