Browse Source

Cache modules and cables in engine by ID. Add lock to Engine::reset/randomize/bypassModule(). Remove lock from Engine::get/setParam and get/setSmoothParam.

tags/v2.0.0
Andrew Belt 5 years ago
parent
commit
6f7f0cc7b3
3 changed files with 139 additions and 129 deletions
  1. +2
    -1
      include/engine/Module.hpp
  2. +1
    -1
      src/audio.cpp
  3. +136
    -127
      src/engine/Engine.cpp

+ 2
- 1
include/engine/Module.hpp View File

@@ -303,8 +303,9 @@ struct Module {
/** DEPRECATED. Override `onSampleRateChange(e)` instead. */ /** DEPRECATED. Override `onSampleRateChange(e)` instead. */
virtual void onSampleRateChange() {} virtual void onSampleRateChange() {}


// private
/** private */
float& cpuTime(); float& cpuTime();
/** private */
bool& bypassed(); bool& bypassed();
}; };




+ 1
- 1
src/audio.cpp View File

@@ -87,8 +87,8 @@ void Device::onCloseStream() {
//////////////////// ////////////////////


Port::Port() { Port::Port() {
reset();
context = contextGet(); context = contextGet();
reset();
} }


Port::~Port() { Port::~Port() {


+ 136
- 127
src/engine/Engine.cpp View File

@@ -185,7 +185,13 @@ struct Engine::Internal {
std::vector<Module*> modules; std::vector<Module*> modules;
std::vector<Cable*> cables; std::vector<Cable*> cables;
std::set<ParamHandle*> paramHandles; std::set<ParamHandle*> paramHandles;
std::map<std::tuple<int, int>, ParamHandle*> paramHandleCache;

// moduleId
std::map<int, Module*> modulesCache;
// cableId
std::map<int, Cable*> cablesCache;
// (moduleId, paramId)
std::map<std::tuple<int, int>, ParamHandle*> paramHandlesCache;


float sampleRate = 0.f; float sampleRate = 0.f;
float sampleTime = 0.f; float sampleTime = 0.f;
@@ -195,6 +201,7 @@ struct Engine::Internal {
int stepFrames = 0; int stepFrames = 0;
Module* primaryModule = NULL; Module* primaryModule = NULL;


// For generating new IDs for added objects
int nextModuleId = 0; int nextModuleId = 0;
int nextCableId = 0; int nextCableId = 0;


@@ -214,6 +221,59 @@ struct Engine::Internal {
}; };




static void Engine_updateExpander(Engine* that, Module::Expander* expander) {
if (expander->moduleId >= 0) {
if (!expander->module || expander->module->id != expander->moduleId) {
expander->module = that->getModule(expander->moduleId);
}
}
else {
if (expander->module) {
expander->module = NULL;
}
}
}


static void Engine_relaunchWorkers(Engine* that, int threadCount) {
Engine::Internal* internal = that->internal;
if (threadCount == internal->threadCount)
return;

if (internal->threadCount > 0) {
// Stop engine workers
for (EngineWorker& worker : internal->workers) {
worker.requestStop();
}
internal->engineBarrier.wait();

// Join and destroy engine workers
for (EngineWorker& worker : internal->workers) {
worker.join();
}
internal->workers.resize(0);
}

// Configure engine
internal->threadCount = threadCount;

// Set barrier counts
internal->engineBarrier.total = threadCount;
internal->workerBarrier.total = threadCount;

if (threadCount > 0) {
// Create and start engine workers
internal->workers.resize(threadCount - 1);
for (int id = 1; id < threadCount; id++) {
EngineWorker& worker = internal->workers[id - 1];
worker.id = id;
worker.engine = that;
worker.start();
}
}
}


static void Port_step(Port* that, float deltaTime) { static void Port_step(Port* that, float deltaTime) {
// Set plug lights // Set plug lights
if (that->channels == 0) { if (that->channels == 0) {
@@ -371,52 +431,60 @@ static void Engine_stepModules(Engine* that) {
} }




static void Engine_updateExpander(Engine* that, Module::Expander* expander) {
if (expander->moduleId >= 0) {
if (!expander->module || expander->module->id != expander->moduleId) {
expander->module = that->getModule(expander->moduleId);
}
}
else {
if (expander->module) {
expander->module = NULL;
}
static void Port_setDisconnected(Port* that) {
that->channels = 0;
for (int c = 0; c < PORT_MAX_CHANNELS; c++) {
that->voltages[c] = 0.f;
} }
} }




static void Engine_relaunchWorkers(Engine* that, int threadCount) {
Engine::Internal* internal = that->internal;
static void Port_setConnected(Port* that) {
if (that->channels > 0)
return;
that->channels = 1;
}


if (internal->threadCount > 0) {
// Stop engine workers
for (EngineWorker& worker : internal->workers) {
worker.requestStop();
}
internal->engineBarrier.wait();


// Join and destroy engine workers
for (EngineWorker& worker : internal->workers) {
worker.join();
static void Engine_updateConnected(Engine* that) {
// Find disconnected ports
std::set<Port*> disconnectedPorts;
for (Module* module : that->internal->modules) {
for (Input& input : module->inputs) {
disconnectedPorts.insert(&input);
}
for (Output& output : module->outputs) {
disconnectedPorts.insert(&output);
} }
internal->workers.resize(0);
} }
for (Cable* cable : that->internal->cables) {
// Connect input
Input& input = cable->inputModule->inputs[cable->inputId];
auto inputIt = disconnectedPorts.find(&input);
if (inputIt != disconnectedPorts.end())
disconnectedPorts.erase(inputIt);
Port_setConnected(&input);
// Connect output
Output& output = cable->outputModule->outputs[cable->outputId];
auto outputIt = disconnectedPorts.find(&output);
if (outputIt != disconnectedPorts.end())
disconnectedPorts.erase(outputIt);
Port_setConnected(&output);
}
// Disconnect ports that have no cable
for (Port* port : disconnectedPorts) {
Port_setDisconnected(port);
}
}


// Configure engine
internal->threadCount = threadCount;

// Set barrier counts
internal->engineBarrier.total = threadCount;
internal->workerBarrier.total = threadCount;


if (threadCount > 0) {
// Create and start engine workers
internal->workers.resize(threadCount - 1);
for (int id = 1; id < threadCount; id++) {
EngineWorker& worker = internal->workers[id - 1];
worker.id = id;
worker.engine = that;
worker.start();
static void Engine_refreshParamHandleCache(Engine* that) {
// Clear cache
that->internal->paramHandlesCache.clear();
// Add active ParamHandles to cache
for (ParamHandle* paramHandle : that->internal->paramHandles) {
if (paramHandle->moduleId >= 0) {
that->internal->paramHandlesCache[std::make_tuple(paramHandle->moduleId, paramHandle->paramId)] = paramHandle;
} }
} }
} }
@@ -440,7 +508,10 @@ Engine::~Engine() {
assert(internal->cables.empty()); assert(internal->cables.empty());
assert(internal->modules.empty()); assert(internal->modules.empty());
assert(internal->paramHandles.empty()); assert(internal->paramHandles.empty());
assert(internal->paramHandleCache.empty());

assert(internal->modulesCache.empty());
assert(internal->cablesCache.empty());
assert(internal->paramHandlesCache.empty());


delete internal; delete internal;
} }
@@ -484,7 +555,7 @@ void Engine::step(int frames) {
// Set sample rate // Set sample rate
if (internal->sampleRate != settings::sampleRate) { if (internal->sampleRate != settings::sampleRate) {
internal->sampleRate = settings::sampleRate; internal->sampleRate = settings::sampleRate;
internal->sampleTime = 1 / internal->sampleRate;
internal->sampleTime = 1.f / internal->sampleRate;
Module::SampleRateChangeEvent e; Module::SampleRateChangeEvent e;
e.sampleRate = internal->sampleRate; e.sampleRate = internal->sampleRate;
e.sampleTime = internal->sampleTime; e.sampleTime = internal->sampleTime;
@@ -493,17 +564,15 @@ void Engine::step(int frames) {
} }
} }


// Launch workers
if (internal->threadCount != settings::threadCount) {
Engine_relaunchWorkers(this, settings::threadCount);
}

// Update expander pointers // Update expander pointers
for (Module* module : internal->modules) { for (Module* module : internal->modules) {
Engine_updateExpander(this, &module->leftExpander); Engine_updateExpander(this, &module->leftExpander);
Engine_updateExpander(this, &module->rightExpander); Engine_updateExpander(this, &module->rightExpander);
} }


// Launch workers
Engine_relaunchWorkers(this, settings::threadCount);

// Step modules // Step modules
for (int i = 0; i < frames; i++) { for (int i = 0; i < frames; i++) {
Engine_stepModules(this); Engine_stepModules(this);
@@ -608,15 +677,16 @@ void Engine::addModule(Module* module) {
else { else {
// Manual ID // Manual ID
// Check that the ID is not already taken // Check that the ID is not already taken
for (Module* m : internal->modules) {
assert(module->id != m->id);
}
auto it = internal->modulesCache.find(module->id);
assert(it == internal->modulesCache.end());
// If ID is higher than engine's next assigned ID, enlarge it.
if (module->id >= internal->nextModuleId) { if (module->id >= internal->nextModuleId) {
internal->nextModuleId = module->id + 1; internal->nextModuleId = module->id + 1;
} }
} }
// Add module // Add module
internal->modules.push_back(module); internal->modules.push_back(module);
internal->modulesCache[module->id] = module;
// Trigger Add event // Trigger Add event
Module::AddEvent eAdd; Module::AddEvent eAdd;
module->onAdd(eAdd); module->onAdd(eAdd);
@@ -666,23 +736,22 @@ void Engine::removeModule(Module* module) {
if (internal->primaryModule == module) if (internal->primaryModule == module)
internal->primaryModule = NULL; internal->primaryModule = NULL;
// Remove module // Remove module
internal->modulesCache.erase(module->id);
internal->modules.erase(it); internal->modules.erase(it);
} }




Module* Engine::getModule(int moduleId) { Module* Engine::getModule(int moduleId) {
SharedLock lock(internal->mutex); SharedLock lock(internal->mutex);
// Find module by id
for (Module* module : internal->modules) {
if (module->id == moduleId)
return module;
}
return NULL;
auto it = internal->modulesCache.find(moduleId);
if (it == internal->modulesCache.end())
return NULL;
return it->second;
} }




void Engine::resetModule(Module* module) { void Engine::resetModule(Module* module) {
SharedLock lock(internal->mutex);
ExclusiveSharedLock lock(internal->mutex);
assert(module); assert(module);


Module::ResetEvent eReset; Module::ResetEvent eReset;
@@ -691,7 +760,7 @@ void Engine::resetModule(Module* module) {




void Engine::randomizeModule(Module* module) { void Engine::randomizeModule(Module* module) {
SharedLock lock(internal->mutex);
ExclusiveSharedLock lock(internal->mutex);
assert(module); assert(module);


Module::RandomizeEvent eRandomize; Module::RandomizeEvent eRandomize;
@@ -700,8 +769,9 @@ void Engine::randomizeModule(Module* module) {




void Engine::bypassModule(Module* module, bool bypassed) { void Engine::bypassModule(Module* module, bool bypassed) {
SharedLock lock(internal->mutex);
ExclusiveSharedLock lock(internal->mutex);
assert(module); assert(module);

if (module->bypassed() == bypassed) if (module->bypassed() == bypassed)
return; return;
// Clear outputs and set to 1 channel // Clear outputs and set to 1 channel
@@ -709,6 +779,7 @@ void Engine::bypassModule(Module* module, bool bypassed) {
// This zeros all voltages, but the channel is set to 1 if connected // This zeros all voltages, but the channel is set to 1 if connected
output.setChannels(0); output.setChannels(0);
} }
// Set bypassed
module->bypassed() = bypassed; module->bypassed() = bypassed;
// Trigger event // Trigger event
if (bypassed) { if (bypassed) {
@@ -734,53 +805,6 @@ void Engine::moduleFromJson(Module* module, json_t* rootJ) {
} }




static void Port_setDisconnected(Port* that) {
that->channels = 0;
for (int c = 0; c < PORT_MAX_CHANNELS; c++) {
that->voltages[c] = 0.f;
}
}


static void Port_setConnected(Port* that) {
if (that->channels > 0)
return;
that->channels = 1;
}


static void Engine_updateConnected(Engine* that) {
// Find disconnected ports
std::set<Port*> disconnectedPorts;
for (Module* module : that->internal->modules) {
for (Input& input : module->inputs) {
disconnectedPorts.insert(&input);
}
for (Output& output : module->outputs) {
disconnectedPorts.insert(&output);
}
}
for (Cable* cable : that->internal->cables) {
// Connect input
Input& input = cable->inputModule->inputs[cable->inputId];
auto inputIt = disconnectedPorts.find(&input);
if (inputIt != disconnectedPorts.end())
disconnectedPorts.erase(inputIt);
Port_setConnected(&input);
// Connect output
Output& output = cable->outputModule->outputs[cable->outputId];
auto outputIt = disconnectedPorts.find(&output);
if (outputIt != disconnectedPorts.end())
disconnectedPorts.erase(outputIt);
Port_setConnected(&output);
}
// Disconnect ports that have no cable
for (Port* port : disconnectedPorts) {
Port_setDisconnected(port);
}
}


void Engine::addCable(Cable* cable) { void Engine::addCable(Cable* cable) {
ExclusiveSharedLock lock(internal->mutex); ExclusiveSharedLock lock(internal->mutex);
assert(cable); assert(cable);
@@ -815,6 +839,7 @@ void Engine::addCable(Cable* cable) {
} }
// Add the cable // Add the cable
internal->cables.push_back(cable); internal->cables.push_back(cable);
internal->cablesCache[cable->id] = cable;
Engine_updateConnected(this); Engine_updateConnected(this);
// Trigger input port event // Trigger input port event
{ {
@@ -842,6 +867,7 @@ void Engine::removeCable(Cable* cable) {
auto it = std::find(internal->cables.begin(), internal->cables.end(), cable); auto it = std::find(internal->cables.begin(), internal->cables.end(), cable);
assert(it != internal->cables.end()); assert(it != internal->cables.end());
// Remove the cable // Remove the cable
internal->cablesCache.erase(cable->id);
internal->cables.erase(it); internal->cables.erase(it);
Engine_updateConnected(this); Engine_updateConnected(this);
bool outputIsConnected = false; bool outputIsConnected = false;
@@ -872,17 +898,14 @@ void Engine::removeCable(Cable* cable) {


Cable* Engine::getCable(int cableId) { Cable* Engine::getCable(int cableId) {
SharedLock lock(internal->mutex); SharedLock lock(internal->mutex);
// Find cable by id
for (Cable* cable : internal->cables) {
if (cable->id == cableId)
return cable;
}
return NULL;
auto it = internal->cablesCache.find(cableId);
if (it == internal->cablesCache.end())
return NULL;
return it->second;
} }




void Engine::setParam(Module* module, int paramId, float value) { void Engine::setParam(Module* module, int paramId, float value) {
SharedLock lock(internal->mutex);
// If param is being smoothed, cancel smoothing. // If param is being smoothed, cancel smoothing.
if (internal->smoothModule == module && internal->smoothParamId == paramId) { if (internal->smoothModule == module && internal->smoothParamId == paramId) {
internal->smoothModule = NULL; internal->smoothModule = NULL;
@@ -893,13 +916,11 @@ void Engine::setParam(Module* module, int paramId, float value) {




float Engine::getParam(Module* module, int paramId) { float Engine::getParam(Module* module, int paramId) {
SharedLock lock(internal->mutex);
return module->params[paramId].value; return module->params[paramId].value;
} }




void Engine::setSmoothParam(Module* module, int paramId, float value) { void Engine::setSmoothParam(Module* module, int paramId, float value) {
SharedLock lock(internal->mutex);
// If another param is being smoothed, jump value // If another param is being smoothed, jump value
if (internal->smoothModule && !(internal->smoothModule == module && internal->smoothParamId == paramId)) { if (internal->smoothModule && !(internal->smoothModule == module && internal->smoothParamId == paramId)) {
internal->smoothModule->params[internal->smoothParamId].value = internal->smoothValue; internal->smoothModule->params[internal->smoothParamId].value = internal->smoothValue;
@@ -912,25 +933,12 @@ void Engine::setSmoothParam(Module* module, int paramId, float value) {




float Engine::getSmoothParam(Module* module, int paramId) { float Engine::getSmoothParam(Module* module, int paramId) {
SharedLock lock(internal->mutex);
if (internal->smoothModule == module && internal->smoothParamId == paramId) if (internal->smoothModule == module && internal->smoothParamId == paramId)
return internal->smoothValue; return internal->smoothValue;
return module->params[paramId].value; return module->params[paramId].value;
} }




static void Engine_refreshParamHandleCache(Engine* that) {
// Clear cache
that->internal->paramHandleCache.clear();
// Add active ParamHandles to cache
for (ParamHandle* paramHandle : that->internal->paramHandles) {
if (paramHandle->moduleId >= 0) {
that->internal->paramHandleCache[std::make_tuple(paramHandle->moduleId, paramHandle->paramId)] = paramHandle;
}
}
}


void Engine::addParamHandle(ParamHandle* paramHandle) { void Engine::addParamHandle(ParamHandle* paramHandle) {
ExclusiveSharedLock lock(internal->mutex); ExclusiveSharedLock lock(internal->mutex);
// New ParamHandles must be blank. // New ParamHandles must be blank.
@@ -943,6 +951,7 @@ void Engine::addParamHandle(ParamHandle* paramHandle) {


// Add it // Add it
internal->paramHandles.insert(paramHandle); internal->paramHandles.insert(paramHandle);
// No need to refresh the cache because the moduleId is not set.
} }




@@ -961,8 +970,8 @@ void Engine::removeParamHandle(ParamHandle* paramHandle) {


ParamHandle* Engine::getParamHandle(int moduleId, int paramId) { ParamHandle* Engine::getParamHandle(int moduleId, int paramId) {
SharedLock lock(internal->mutex); SharedLock lock(internal->mutex);
auto it = internal->paramHandleCache.find(std::make_tuple(moduleId, paramId));
if (it == internal->paramHandleCache.end())
auto it = internal->paramHandlesCache.find(std::make_tuple(moduleId, paramId));
if (it == internal->paramHandlesCache.end())
return NULL; return NULL;
return it->second; return it->second;
} }


Loading…
Cancel
Save