Browse Source

Master audio module (the module that clocks Engine) makes more sense.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
4567cc4220
4 changed files with 67 additions and 67 deletions
  1. +7
    -7
      include/engine/Engine.hpp
  2. +4
    -4
      include/engine/Module.hpp
  3. +23
    -23
      src/core/AudioInterface.cpp
  4. +33
    -33
      src/engine/Engine.cpp

+ 7
- 7
include/engine/Engine.hpp View File

@@ -30,18 +30,18 @@ struct Engine {
void clear();
INTERNAL void clear_NoLock();
/** 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.
*/
void stepBlock(int frames);
/** 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.
*/
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.
*/
@@ -225,7 +225,7 @@ struct Engine {
*/
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();
};


+ 4
- 4
include/engine/Module.hpp View File

@@ -410,11 +410,11 @@ struct Module {
*/
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. */
virtual void onAdd() {}


+ 23
- 23
src/core/AudioInterface.cpp View File

@@ -36,24 +36,24 @@ struct AudioInterfacePort : audio::Port {
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 {
// 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".
if (isPrimaryCached) {
if (isMasterCached) {
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.
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();
// DEBUG("%p: clearing engine output", this);
}

if (deviceNumInputs > 0) {
// Always clear engine output if primary
if (isPrimaryCached) {
// Always clear engine output if master
if (isMasterCached) {
engineOutputBuffer.clear();
}
// 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 {
// Step engine
if (isPrimary() && requestedEngineFrames > 0) {
if (isMaster() && requestedEngineFrames > 0) {
// DEBUG("%p: %d block, stepping %d", this, frames, requestedEngineFrames);
APP->engine->stepBlock(requestedEngineFrames);
}
}

void processOutput(float* output, int outputStride, int frames) override {
// bool isPrimaryCached = isPrimary();
// bool isMasterCached = isMaster();
float engineSampleRate = APP->engine->getSampleRate();
float sampleRateRatio = engineSampleRate / deviceSampleRate;

@@ -148,7 +148,7 @@ struct AudioInterfacePort : audio::Port {
// 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 {
@@ -388,12 +388,12 @@ struct AudioInterface : Module {

/** 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(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));


+ 33
- 33
src/engine/Engine.cpp View File

@@ -235,7 +235,7 @@ struct Engine::Internal {
std::vector<Module*> modules;
std::vector<Cable*> cables;
std::set<ParamHandle*> paramHandles;
Module* primaryModule = NULL;
Module* masterModule = NULL;

// moduleId
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;
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;

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();
}
}


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)
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 (module == internal->smoothModule) {
@@ -1225,9 +1225,9 @@ json_t* Engine::toJson() {
}
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;
@@ -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);

while (that->internal->fallbackRunning) {
if (!that->getPrimaryModule()) {
if (!that->getMasterModule()) {
// Step blocks and wait
double start = system::getTime();
int frames = std::floor(that->getSampleRate() / 60);
@@ -1357,10 +1357,10 @@ static void Engine_fallbackRun(Engine* that) {
}
}
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);
that->internal->fallbackCv.wait(lock, [&]() {
return !that->internal->fallbackRunning || !that->getPrimaryModule();
return !that->internal->fallbackRunning || !that->getMasterModule();
});
}
}


Loading…
Cancel
Save