| @@ -30,18 +30,18 @@ struct Engine { | |||||
| void clear(); | void clear(); | ||||
| INTERNAL void clear_NoLock(); | INTERNAL void clear_NoLock(); | ||||
| /** Advances the engine by `frames` frames. | /** Advances the engine by `frames` frames. | ||||
| Only call this method from the primary module. | |||||
| Only call this method from the master module. | |||||
| Read-locks. Also locks so only one stepBlock() can be called simultaneously or recursively. | Read-locks. Also locks so only one stepBlock() can be called simultaneously or recursively. | ||||
| */ | */ | ||||
| void stepBlock(int frames); | void stepBlock(int frames); | ||||
| /** Module does not need to belong to the Engine. | /** Module does not need to belong to the Engine. | ||||
| However, Engine will unset the primary module when it is removed from the Engine. | |||||
| NULL will unset the primary module. | |||||
| However, Engine will unset the master module when it is removed from the Engine. | |||||
| NULL will unset the master module. | |||||
| Write-locks. | Write-locks. | ||||
| */ | */ | ||||
| void setPrimaryModule(Module* module); | |||||
| INTERNAL void setPrimaryModule_NoLock(Module* module); | |||||
| Module* getPrimaryModule(); | |||||
| void setMasterModule(Module* module); | |||||
| INTERNAL void setMasterModule_NoLock(Module* module); | |||||
| Module* getMasterModule(); | |||||
| /** Returns the sample rate used by the engine for stepping each module. | /** Returns the sample rate used by the engine for stepping each module. | ||||
| */ | */ | ||||
| @@ -225,7 +225,7 @@ struct Engine { | |||||
| */ | */ | ||||
| void fromJson(json_t* rootJ); | void fromJson(json_t* rootJ); | ||||
| /** If no primary module is set, the fallback Engine thread will step blocks, using the CPU clock for timing. | |||||
| /** If no master module is set, the fallback Engine thread will step blocks, using the CPU clock for timing. | |||||
| */ | */ | ||||
| void startFallbackThread(); | void startFallbackThread(); | ||||
| }; | }; | ||||
| @@ -410,11 +410,11 @@ struct Module { | |||||
| */ | */ | ||||
| virtual void onSave(const SaveEvent& e) {} | virtual void onSave(const SaveEvent& e) {} | ||||
| struct SetPrimaryEvent {}; | |||||
| virtual void onSetPrimary(const SetPrimaryEvent& e) {} | |||||
| struct SetMasterEvent {}; | |||||
| virtual void onSetMaster(const SetMasterEvent& e) {} | |||||
| struct UnsetPrimaryEvent {}; | |||||
| virtual void onUnsetPrimary(const UnsetPrimaryEvent& e) {} | |||||
| struct UnsetMasterEvent {}; | |||||
| virtual void onUnsetMaster(const UnsetMasterEvent& e) {} | |||||
| /** DEPRECATED. Override `onAdd(e)` instead. */ | /** DEPRECATED. Override `onAdd(e)` instead. */ | ||||
| virtual void onAdd() {} | virtual void onAdd() {} | ||||
| @@ -36,24 +36,24 @@ struct AudioInterfacePort : audio::Port { | |||||
| outputSrc.setQuality(6); | outputSrc.setQuality(6); | ||||
| } | } | ||||
| void setPrimary() { | |||||
| APP->engine->setPrimaryModule(module); | |||||
| void setMaster() { | |||||
| APP->engine->setMasterModule(module); | |||||
| } | } | ||||
| bool isPrimary() { | |||||
| return APP->engine->getPrimaryModule() == module; | |||||
| bool isMaster() { | |||||
| return APP->engine->getMasterModule() == module; | |||||
| } | } | ||||
| void processInput(const float* input, int inputStride, int frames) override { | void processInput(const float* input, int inputStride, int frames) override { | ||||
| // DEBUG("%p: new device block ____________________________", this); | // DEBUG("%p: new device block ____________________________", this); | ||||
| // Claim primary module if there is none | |||||
| if (!APP->engine->getPrimaryModule()) { | |||||
| setPrimary(); | |||||
| // Claim master module if there is none | |||||
| if (!APP->engine->getMasterModule()) { | |||||
| setMaster(); | |||||
| } | } | ||||
| bool isPrimaryCached = isPrimary(); | |||||
| bool isMasterCached = isMaster(); | |||||
| // Set sample rate of engine if engine sample rate is "auto". | // Set sample rate of engine if engine sample rate is "auto". | ||||
| if (isPrimaryCached) { | |||||
| if (isMasterCached) { | |||||
| APP->engine->setSuggestedSampleRate(deviceSampleRate); | APP->engine->setSuggestedSampleRate(deviceSampleRate); | ||||
| } | } | ||||
| @@ -64,15 +64,15 @@ struct AudioInterfacePort : audio::Port { | |||||
| // Consider engine buffers "too full" if they contain a bit more than the audio device's number of frames, converted to engine sample rate. | // Consider engine buffers "too full" if they contain a bit more than the audio device's number of frames, converted to engine sample rate. | ||||
| int maxEngineFrames = (int) std::ceil(frames * sampleRateRatio * 2.0) - 1; | int maxEngineFrames = (int) std::ceil(frames * sampleRateRatio * 2.0) - 1; | ||||
| // If the engine output buffer is too full, clear it to keep latency low. No need to clear if primary because it's always cleared below. | |||||
| if (!isPrimaryCached && (int) engineOutputBuffer.size() > maxEngineFrames) { | |||||
| // If the engine output buffer is too full, clear it to keep latency low. No need to clear if master because it's always cleared below. | |||||
| if (!isMasterCached && (int) engineOutputBuffer.size() > maxEngineFrames) { | |||||
| engineOutputBuffer.clear(); | engineOutputBuffer.clear(); | ||||
| // DEBUG("%p: clearing engine output", this); | // DEBUG("%p: clearing engine output", this); | ||||
| } | } | ||||
| if (deviceNumInputs > 0) { | if (deviceNumInputs > 0) { | ||||
| // Always clear engine output if primary | |||||
| if (isPrimaryCached) { | |||||
| // Always clear engine output if master | |||||
| if (isMasterCached) { | |||||
| engineOutputBuffer.clear(); | engineOutputBuffer.clear(); | ||||
| } | } | ||||
| // Set up sample rate converter | // Set up sample rate converter | ||||
| @@ -102,14 +102,14 @@ struct AudioInterfacePort : audio::Port { | |||||
| void processBuffer(const float* input, int inputStride, float* output, int outputStride, int frames) override { | void processBuffer(const float* input, int inputStride, float* output, int outputStride, int frames) override { | ||||
| // Step engine | // Step engine | ||||
| if (isPrimary() && requestedEngineFrames > 0) { | |||||
| if (isMaster() && requestedEngineFrames > 0) { | |||||
| // DEBUG("%p: %d block, stepping %d", this, frames, requestedEngineFrames); | // DEBUG("%p: %d block, stepping %d", this, frames, requestedEngineFrames); | ||||
| APP->engine->stepBlock(requestedEngineFrames); | APP->engine->stepBlock(requestedEngineFrames); | ||||
| } | } | ||||
| } | } | ||||
| void processOutput(float* output, int outputStride, int frames) override { | void processOutput(float* output, int outputStride, int frames) override { | ||||
| // bool isPrimaryCached = isPrimary(); | |||||
| // bool isMasterCached = isMaster(); | |||||
| float engineSampleRate = APP->engine->getSampleRate(); | float engineSampleRate = APP->engine->getSampleRate(); | ||||
| float sampleRateRatio = engineSampleRate / deviceSampleRate; | float sampleRateRatio = engineSampleRate / deviceSampleRate; | ||||
| @@ -148,7 +148,7 @@ struct AudioInterfacePort : audio::Port { | |||||
| // DEBUG("%p: clearing engine input", this); | // DEBUG("%p: clearing engine input", this); | ||||
| } | } | ||||
| // DEBUG("%p %s:\tframes %d requestedEngineFrames %d\toutputBuffer %d engineInputBuffer %d\t", this, isPrimaryCached ? "primary" : "secondary", frames, requestedEngineFrames, engineOutputBuffer.size(), engineInputBuffer.size()); | |||||
| // DEBUG("%p %s:\tframes %d requestedEngineFrames %d\toutputBuffer %d engineInputBuffer %d\t", this, isMasterCached ? "master" : "secondary", frames, requestedEngineFrames, engineOutputBuffer.size(), engineInputBuffer.size()); | |||||
| } | } | ||||
| void onStartStream() override { | void onStartStream() override { | ||||
| @@ -388,12 +388,12 @@ struct AudioInterface : Module { | |||||
| /** Must be called when the Engine mutex is unlocked. | /** Must be called when the Engine mutex is unlocked. | ||||
| */ | */ | ||||
| void setPrimary() { | |||||
| APP->engine->setPrimaryModule(this); | |||||
| void setMaster() { | |||||
| APP->engine->setMasterModule(this); | |||||
| } | } | ||||
| bool isPrimary() { | |||||
| return APP->engine->getPrimaryModule() == this; | |||||
| bool isMaster() { | |||||
| return APP->engine->getMasterModule() == this; | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -561,9 +561,9 @@ struct AudioInterfaceWidget : ModuleWidget { | |||||
| menu->addChild(new MenuSeparator); | menu->addChild(new MenuSeparator); | ||||
| menu->addChild(createCheckMenuItem("Primary audio module", | |||||
| [=]() {return module->isPrimary();}, | |||||
| [=]() {module->setPrimary();} | |||||
| menu->addChild(createCheckMenuItem("Master audio module", | |||||
| [=]() {return module->isMaster();}, | |||||
| [=]() {module->setMaster();} | |||||
| )); | )); | ||||
| menu->addChild(createBoolPtrMenuItem("DC blocker", &module->dcFilterEnabled)); | menu->addChild(createBoolPtrMenuItem("DC blocker", &module->dcFilterEnabled)); | ||||
| @@ -235,7 +235,7 @@ 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; | ||||
| Module* primaryModule = NULL; | |||||
| Module* masterModule = NULL; | |||||
| // moduleId | // moduleId | ||||
| std::map<int64_t, Module*> modulesCache; | std::map<int64_t, Module*> modulesCache; | ||||
| @@ -631,41 +631,41 @@ void Engine::stepBlock(int frames) { | |||||
| } | } | ||||
| void Engine::setPrimaryModule(Module* module) { | |||||
| if (module == internal->primaryModule) | |||||
| void Engine::setMasterModule(Module* module) { | |||||
| if (module == internal->masterModule) | |||||
| return; | return; | ||||
| WriteLock lock(internal->mutex); | WriteLock lock(internal->mutex); | ||||
| setPrimaryModule_NoLock(module); | |||||
| setMasterModule_NoLock(module); | |||||
| } | } | ||||
| void Engine::setPrimaryModule_NoLock(Module* module) { | |||||
| if (module == internal->primaryModule) | |||||
| void Engine::setMasterModule_NoLock(Module* module) { | |||||
| if (module == internal->masterModule) | |||||
| return; | return; | ||||
| if (internal->primaryModule) { | |||||
| // Dispatch UnsetPrimaryEvent | |||||
| Module::UnsetPrimaryEvent e; | |||||
| internal->primaryModule->onUnsetPrimary(e); | |||||
| if (internal->masterModule) { | |||||
| // Dispatch UnsetMasterEvent | |||||
| Module::UnsetMasterEvent e; | |||||
| internal->masterModule->onUnsetMaster(e); | |||||
| } | } | ||||
| internal->primaryModule = module; | |||||
| internal->masterModule = module; | |||||
| if (internal->primaryModule) { | |||||
| // Dispatch SetPrimaryEvent | |||||
| Module::SetPrimaryEvent e; | |||||
| internal->primaryModule->onSetPrimary(e); | |||||
| if (internal->masterModule) { | |||||
| // Dispatch SetMasterEvent | |||||
| Module::SetMasterEvent e; | |||||
| internal->masterModule->onSetMaster(e); | |||||
| } | } | ||||
| // Wake up fallback thread if primary module was unset | |||||
| if (!internal->primaryModule) { | |||||
| // Wake up fallback thread if master module was unset | |||||
| if (!internal->masterModule) { | |||||
| internal->fallbackCv.notify_all(); | internal->fallbackCv.notify_all(); | ||||
| } | } | ||||
| } | } | ||||
| Module* Engine::getPrimaryModule() { | |||||
| return internal->primaryModule; | |||||
| Module* Engine::getMasterModule() { | |||||
| return internal->masterModule; | |||||
| } | } | ||||
| @@ -833,9 +833,9 @@ void Engine::removeModule_NoLock(Module* module) { | |||||
| if (paramHandle->moduleId == module->id) | if (paramHandle->moduleId == module->id) | ||||
| paramHandle->module = NULL; | paramHandle->module = NULL; | ||||
| } | } | ||||
| // Unset primary module | |||||
| if (getPrimaryModule() == module) { | |||||
| setPrimaryModule_NoLock(NULL); | |||||
| // Unset master module | |||||
| if (getMasterModule() == module) { | |||||
| setMasterModule_NoLock(NULL); | |||||
| } | } | ||||
| // If a param is being smoothed on this module, stop smoothing it immediately | // If a param is being smoothed on this module, stop smoothing it immediately | ||||
| if (module == internal->smoothModule) { | if (module == internal->smoothModule) { | ||||
| @@ -1225,9 +1225,9 @@ json_t* Engine::toJson() { | |||||
| } | } | ||||
| json_object_set_new(rootJ, "cables", cablesJ); | json_object_set_new(rootJ, "cables", cablesJ); | ||||
| // primaryModule | |||||
| if (internal->primaryModule) { | |||||
| json_object_set_new(rootJ, "primaryModuleId", json_integer(internal->primaryModule->id)); | |||||
| // masterModule | |||||
| if (internal->masterModule) { | |||||
| json_object_set_new(rootJ, "masterModuleId", json_integer(internal->masterModule->id)); | |||||
| } | } | ||||
| return rootJ; | return rootJ; | ||||
| @@ -1313,11 +1313,11 @@ void Engine::fromJson(json_t* rootJ) { | |||||
| } | } | ||||
| } | } | ||||
| // primaryModule | |||||
| json_t* primaryModuleIdJ = json_object_get(rootJ, "primaryModuleId"); | |||||
| if (primaryModuleIdJ) { | |||||
| Module* primaryModule = getModule(json_integer_value(primaryModuleIdJ)); | |||||
| setPrimaryModule(primaryModule); | |||||
| // masterModule | |||||
| json_t* masterModuleIdJ = json_object_get(rootJ, "masterModuleId"); | |||||
| if (masterModuleIdJ) { | |||||
| Module* masterModule = getModule(json_integer_value(masterModuleIdJ)); | |||||
| setMasterModule(masterModule); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1344,7 +1344,7 @@ static void Engine_fallbackRun(Engine* that) { | |||||
| contextSet(that->internal->context); | contextSet(that->internal->context); | ||||
| while (that->internal->fallbackRunning) { | while (that->internal->fallbackRunning) { | ||||
| if (!that->getPrimaryModule()) { | |||||
| if (!that->getMasterModule()) { | |||||
| // Step blocks and wait | // Step blocks and wait | ||||
| double start = system::getTime(); | double start = system::getTime(); | ||||
| int frames = std::floor(that->getSampleRate() / 60); | int frames = std::floor(that->getSampleRate() / 60); | ||||
| @@ -1357,10 +1357,10 @@ static void Engine_fallbackRun(Engine* that) { | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| // Wait for primary module to be unset, or for the request to stop running | |||||
| // Wait for master module to be unset, or for the request to stop running | |||||
| std::unique_lock<std::mutex> lock(that->internal->fallbackMutex); | std::unique_lock<std::mutex> lock(that->internal->fallbackMutex); | ||||
| that->internal->fallbackCv.wait(lock, [&]() { | that->internal->fallbackCv.wait(lock, [&]() { | ||||
| return !that->internal->fallbackRunning || !that->getPrimaryModule(); | |||||
| return !that->internal->fallbackRunning || !that->getMasterModule(); | |||||
| }); | }); | ||||
| } | } | ||||
| } | } | ||||