Browse Source

Write to `settings::sampleRate` and `threadCount` instead of calling Engine methods.

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
a0e738bc07
5 changed files with 87 additions and 73 deletions
  1. +0
    -3
      include/engine/Engine.hpp
  2. +1
    -0
      include/settings.hpp
  3. +20
    -8
      src/app/Toolbar.cpp
  4. +59
    -62
      src/engine/Engine.cpp
  5. +7
    -0
      src/settings.cpp

+ 0
- 3
include/engine/Engine.hpp View File

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


+ 1
- 0
include/settings.hpp View File

@@ -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;


+ 20
- 8
src/app/Toolbar.cpp View File

@@ -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);



+ 59
- 62
src/engine/Engine.cpp View File

@@ -151,6 +151,7 @@ struct Engine::Internal {
std::thread thread;
VIPMutex vipMutex;

bool realTime = false;
int threadCount = 1;
std::vector<EngineWorker> 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<std::recursive_mutex> lock(that->internal->mutex);
if (!internal->paused) {
std::lock_guard<std::recursive_mutex> 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<double>(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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(internal->mutex);

internal->sampleRate = sampleRate;
internal->sampleTime = 1 / sampleRate;
for (Module *module : internal->modules) {
module->onSampleRateChange();
}
}

float Engine::getSampleRate() {
return internal->sampleRate;
}


+ 7
- 0
src/settings.cpp View File

@@ -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);


Loading…
Cancel
Save