From a0e738bc074dd674079b4fdcd461127c536e0573 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sun, 28 Apr 2019 13:03:56 -0400 Subject: [PATCH] Write to `settings::sampleRate` and `threadCount` instead of calling Engine methods. --- include/engine/Engine.hpp | 3 - include/settings.hpp | 1 + src/app/Toolbar.cpp | 28 ++++++--- src/engine/Engine.cpp | 121 +++++++++++++++++++------------------- src/settings.cpp | 7 +++ 5 files changed, 87 insertions(+), 73 deletions(-) diff --git a/include/engine/Engine.hpp b/include/engine/Engine.hpp index 38ec76db..0f293f58 100644 --- a/include/engine/Engine.hpp +++ b/include/engine/Engine.hpp @@ -20,11 +20,8 @@ struct Engine { void start(); /** Stops engine thread. */ void stop(); - void setThreadCount(int threadCount); - int getThreadCount(); void setPaused(bool paused); bool isPaused(); - void setSampleRate(float sampleRate); float getSampleRate(); /** Returns the inverse of the current sample rate. */ float getSampleTime(); diff --git a/include/settings.hpp b/include/settings.hpp index d23abb45..58997536 100644 --- a/include/settings.hpp +++ b/include/settings.hpp @@ -25,6 +25,7 @@ extern bool invertZoom; extern float cableOpacity; extern float cableTension; extern bool allowCursorLock; +extern bool realTime; extern float sampleRate; extern int threadCount; extern bool paramTooltip; diff --git a/src/app/Toolbar.cpp b/src/app/Toolbar.cpp index f8ef51f6..4343dec2 100644 --- a/src/app/Toolbar.cpp +++ b/src/app/Toolbar.cpp @@ -277,7 +277,7 @@ struct EnginePauseItem : ui::MenuItem { struct SampleRateValueItem : ui::MenuItem { float sampleRate; void onAction(const event::Action &e) override { - APP->engine->setSampleRate(sampleRate); + settings::sampleRate = sampleRate; APP->engine->setPaused(false); } }; @@ -288,7 +288,7 @@ struct SampleRateItem : ui::MenuItem { ui::Menu *menu = new ui::Menu; EnginePauseItem *enginePauseItem = new EnginePauseItem; - enginePauseItem->text = "Pause engine"; + enginePauseItem->text = "Pause"; enginePauseItem->rightText = CHECKMARK(APP->engine->isPaused()); menu->addChild(enginePauseItem); @@ -304,7 +304,7 @@ struct SampleRateItem : ui::MenuItem { if (oversample > 1) item->rightText += string::f("(%dx)", oversample); item->rightText += " "; - item->rightText += CHECKMARK(APP->engine->getSampleRate() == sampleRate); + item->rightText += CHECKMARK(settings::sampleRate == sampleRate); menu->addChild(item); } } @@ -313,6 +313,13 @@ struct SampleRateItem : ui::MenuItem { }; +struct RealTimeItem : ui::MenuItem { + void onAction(const event::Action &e) override { + settings::realTime ^= true; + } +}; + + struct ThreadCountValueItem : ui::MenuItem { int threadCount; void setThreadCount(int threadCount) { @@ -322,18 +329,23 @@ struct ThreadCountValueItem : ui::MenuItem { text += " (most modules)"; else if (threadCount == 1) text += " (lowest CPU usage)"; - rightText = CHECKMARK(APP->engine->getThreadCount() == threadCount); + rightText = CHECKMARK(settings::threadCount == threadCount); } void onAction(const event::Action &e) override { - APP->engine->setThreadCount(threadCount); + settings::threadCount = threadCount; } }; -struct ThreadCount : ui::MenuItem { +struct ThreadCountItem : ui::MenuItem { ui::Menu *createChildMenu() override { ui::Menu *menu = new ui::Menu; + RealTimeItem *realTimeItem = new RealTimeItem; + realTimeItem->text = "Real-time priority"; + realTimeItem->rightText = CHECKMARK(settings::realTime); + menu->addChild(realTimeItem); + int coreCount = system::getLogicalCoreCount(); for (int i = 1; i <= coreCount; i++) { ThreadCountValueItem *item = new ThreadCountValueItem; @@ -378,8 +390,8 @@ struct SettingsButton : MenuButton { sampleRateItem->rightText = RIGHT_ARROW; menu->addChild(sampleRateItem); - ThreadCount *threadCount = new ThreadCount; - threadCount->text = "Thread count"; + ThreadCountItem *threadCount = new ThreadCountItem; + threadCount->text = "Engine threads"; threadCount->rightText = RIGHT_ARROW; menu->addChild(threadCount); diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index d62274d4..75234b6b 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -151,6 +151,7 @@ struct Engine::Internal { std::thread thread; VIPMutex vipMutex; + bool realTime = false; int threadCount = 1; std::vector workers; SpinBarrier engineBarrier; @@ -165,17 +166,11 @@ Engine::Engine() { internal->engineBarrier.total = 1; internal->workerBarrier.total = 1; - setSampleRate(44100.f); - setThreadCount(settings::threadCount); + internal->sampleRate = 44100.f; + internal->sampleTime = 1 / internal->sampleRate; } Engine::~Engine() { - settings::sampleRate = internal->sampleRate; - settings::threadCount = internal->threadCount; - - // Stop worker threads - setThreadCount(1); - // Make sure there are no cables or modules in the rack on destruction. // If this happens, a module must have failed to remove itself before the RackWidget was destroyed. assert(internal->cables.empty()); @@ -300,7 +295,38 @@ static void Engine_updateAdjacent(Engine *that, Module *m) { } } +static void Engine_relaunchWorkers(Engine *that) { + Engine::Internal *internal = that->internal; + assert(1 <= internal->threadCount); + + // Stop all workers + for (EngineWorker &worker : internal->workers) { + worker.stop(); + } + internal->engineBarrier.wait(); + + // Destroy all workers + for (EngineWorker &worker : internal->workers) { + worker.join(); + } + internal->workers.resize(0); + + // Set barrier counts + internal->engineBarrier.total = internal->threadCount; + internal->workerBarrier.total = internal->threadCount; + + // Create workers + internal->workers.resize(internal->threadCount - 1); + for (int id = 1; id < internal->threadCount; id++) { + EngineWorker &worker = internal->workers[id - 1]; + worker.id = id; + worker.engine = that; + worker.start(); + } +} + static void Engine_run(Engine *that) { + Engine::Internal *internal = that->internal; // Set up thread system::setThreadName("Engine"); // system::setThreadRealTime(); @@ -312,13 +338,28 @@ static void Engine_run(Engine *that) { double ahead = 0.0; auto lastTime = std::chrono::high_resolution_clock::now(); - while (that->internal->running) { - that->internal->vipMutex.wait(); + while (internal->running) { + internal->vipMutex.wait(); + + // Set sample rate + if (internal->sampleRate != settings::sampleRate) { + internal->sampleRate = settings::sampleRate; + internal->sampleTime = 1 / internal->sampleRate; + for (Module *module : internal->modules) { + module->onSampleRateChange(); + } + } + + // Launch workers + if (internal->threadCount != settings::threadCount) { + internal->threadCount = settings::threadCount; + Engine_relaunchWorkers(that); + } - if (!that->internal->paused) { - std::lock_guard lock(that->internal->mutex); + if (!internal->paused) { + std::lock_guard lock(internal->mutex); - for (Module *module : that->internal->modules) { + for (Module *module : internal->modules) { Engine_updateAdjacent(that, module); } @@ -328,7 +369,7 @@ static void Engine_run(Engine *that) { } } - double stepTime = mutexSteps * that->internal->sampleTime; + double stepTime = mutexSteps * internal->sampleTime; ahead += stepTime; auto currTime = std::chrono::high_resolution_clock::now(); const double aheadFactor = 2.0; @@ -343,6 +384,10 @@ static void Engine_run(Engine *that) { std::this_thread::sleep_for(std::chrono::duration(stepTime)); } } + + // Stop workers + internal->threadCount = 1; + Engine_relaunchWorkers(that); } void Engine::start() { @@ -355,43 +400,6 @@ void Engine::stop() { internal->thread.join(); } -void Engine::setThreadCount(int threadCount) { - assert(1 <= threadCount); - VIPLock vipLock(internal->vipMutex); - std::lock_guard lock(internal->mutex); - - // Stop all workers - for (EngineWorker &worker : internal->workers) { - worker.stop(); - } - internal->engineBarrier.wait(); - - // Destroy all workers - for (EngineWorker &worker : internal->workers) { - worker.join(); - } - internal->workers.resize(0); - - // Set barrier counts - internal->threadCount = threadCount; - internal->engineBarrier.total = threadCount; - internal->workerBarrier.total = threadCount; - - // Create workers - internal->workers.resize(threadCount - 1); - for (int id = 1; id < threadCount; id++) { - EngineWorker &worker = internal->workers[id - 1]; - worker.id = id; - worker.engine = this; - worker.start(); - } -} - -int Engine::getThreadCount() { - // No lock - return internal->threadCount; -} - void Engine::setPaused(bool paused) { VIPLock vipLock(internal->vipMutex); std::lock_guard lock(internal->mutex); @@ -403,17 +411,6 @@ bool Engine::isPaused() { return internal->paused; } -void Engine::setSampleRate(float sampleRate) { - VIPLock vipLock(internal->vipMutex); - std::lock_guard lock(internal->mutex); - - internal->sampleRate = sampleRate; - internal->sampleTime = 1 / sampleRate; - for (Module *module : internal->modules) { - module->onSampleRateChange(); - } -} - float Engine::getSampleRate() { return internal->sampleRate; } diff --git a/src/settings.cpp b/src/settings.cpp index 52a2c840..0c5b8edd 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -23,6 +23,7 @@ bool invertZoom = false; float cableOpacity = 0.5; float cableTension = 0.5; bool allowCursorLock = true; +bool realTime = false; float sampleRate = 44100.0; int threadCount = 1; bool paramTooltip = false; @@ -57,6 +58,8 @@ json_t *toJson() { json_object_set_new(rootJ, "allowCursorLock", json_boolean(allowCursorLock)); + json_object_set_new(rootJ, "realTime", json_boolean(realTime)); + json_object_set_new(rootJ, "sampleRate", json_real(sampleRate)); json_object_set_new(rootJ, "threadCount", json_integer(threadCount)); @@ -130,6 +133,10 @@ void fromJson(json_t *rootJ) { if (allowCursorLockJ) allowCursorLock = json_is_true(allowCursorLockJ); + json_t *realTimeJ = json_object_get(rootJ, "realTime"); + if (realTimeJ) + realTime = json_boolean_value(realTimeJ); + json_t *sampleRateJ = json_object_get(rootJ, "sampleRate"); if (sampleRateJ) sampleRate = json_number_value(sampleRateJ);