@@ -30,13 +30,14 @@ struct Engine { | |||||
/** 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 primary module. | ||||
*/ | */ | ||||
void stepBlock(int frames); | |||||
void stepBlock(int frames, float suggestedSampleRate = 0.f); | |||||
void setPrimaryModule(Module* module); | void setPrimaryModule(Module* module); | ||||
Module* getPrimaryModule(); | Module* getPrimaryModule(); | ||||
/** Returns the sample rate used by the engine for stepping each module. | /** Returns the sample rate used by the engine for stepping each module. | ||||
*/ | */ | ||||
float getSampleRate(); | float getSampleRate(); | ||||
PRIVATE void setSampleRate(float sampleRate); | |||||
/** Returns the inverse of the current sample rate. | /** Returns the inverse of the current sample rate. | ||||
*/ | */ | ||||
float getSampleTime(); | float getSampleTime(); | ||||
@@ -492,6 +492,16 @@ struct SampleRateItem : ui::MenuItem { | |||||
ui::Menu* createChildMenu() override { | ui::Menu* createChildMenu() override { | ||||
ui::Menu* menu = new ui::Menu; | ui::Menu* menu = new ui::Menu; | ||||
SampleRateValueItem* autoItem = new SampleRateValueItem; | |||||
autoItem->sampleRate = 0; | |||||
autoItem->text = "Auto"; | |||||
if (settings::sampleRate == 0) { | |||||
float sampleRate = APP->engine->getSampleRate(); | |||||
autoItem->rightText = string::f("(%g kHz) ", sampleRate / 1000.f); | |||||
autoItem->rightText += CHECKMARK_STRING; | |||||
} | |||||
menu->addChild(autoItem); | |||||
for (int i = -2; i <= 4; i++) { | for (int i = -2; i <= 4; i++) { | ||||
for (int j = 0; j < 2; j++) { | for (int j = 0; j < 2; j++) { | ||||
float oversample = std::pow(2.f, i); | float oversample = std::pow(2.f, i); | ||||
@@ -500,7 +510,7 @@ struct SampleRateItem : ui::MenuItem { | |||||
SampleRateValueItem* item = new SampleRateValueItem; | SampleRateValueItem* item = new SampleRateValueItem; | ||||
item->sampleRate = sampleRate; | item->sampleRate = sampleRate; | ||||
item->text = string::f("%g kHz", sampleRate / 1000.0); | |||||
item->text = string::f("%g kHz", sampleRate / 1000.f); | |||||
if (oversample > 1.f) { | if (oversample > 1.f) { | ||||
item->rightText += string::f("(%.0fx)", oversample); | item->rightText += string::f("(%.0fx)", oversample); | ||||
} | } | ||||
@@ -245,7 +245,7 @@ struct AudioInterface : Module, audio::Port { | |||||
bool isPrimary = (APP->engine->getPrimaryModule() == this); | bool isPrimary = (APP->engine->getPrimaryModule() == this); | ||||
// Step engine | // Step engine | ||||
if (isPrimary && requestedEngineFrames > 0) { | if (isPrimary && requestedEngineFrames > 0) { | ||||
APP->engine->stepBlock(requestedEngineFrames); | |||||
APP->engine->stepBlock(requestedEngineFrames, getSampleRate()); | |||||
} | } | ||||
} | } | ||||
@@ -182,6 +182,9 @@ struct EngineWorker { | |||||
}; | }; | ||||
static const float FALLBACK_SAMPLE_RATE = 44100; | |||||
struct Engine::Internal { | struct Engine::Internal { | ||||
std::vector<Module*> modules; | std::vector<Module*> modules; | ||||
std::vector<Cable*> cables; | std::vector<Cable*> cables; | ||||
@@ -453,8 +456,7 @@ Engine::Engine() { | |||||
internal = new Internal; | internal = new Internal; | ||||
internal->context = contextGet(); | internal->context = contextGet(); | ||||
internal->sampleRate = 44100.f; | |||||
internal->sampleTime = 1 / internal->sampleRate; | |||||
setSampleRate(FALLBACK_SAMPLE_RATE); | |||||
} | } | ||||
@@ -498,7 +500,7 @@ void Engine::clear() { | |||||
} | } | ||||
void Engine::stepBlock(int frames) { | |||||
void Engine::stepBlock(int frames, float suggestedSampleRate) { | |||||
std::lock_guard<std::mutex> stepLock(internal->blockMutex); | std::lock_guard<std::mutex> stepLock(internal->blockMutex); | ||||
SharedLock lock(internal->mutex); | SharedLock lock(internal->mutex); | ||||
// Configure thread | // Configure thread | ||||
@@ -510,16 +512,14 @@ void Engine::stepBlock(int frames) { | |||||
internal->blockFrames = frames; | internal->blockFrames = frames; | ||||
// Set sample rate | // Set sample rate | ||||
if (internal->sampleRate != settings::sampleRate) { | |||||
internal->sampleRate = settings::sampleRate; | |||||
internal->sampleTime = 1.f / internal->sampleRate; | |||||
// Trigger SampleRateChangeEvent | |||||
Module::SampleRateChangeEvent e; | |||||
e.sampleRate = internal->sampleRate; | |||||
e.sampleTime = internal->sampleTime; | |||||
for (Module* module : internal->modules) { | |||||
module->onSampleRateChange(e); | |||||
} | |||||
if (settings::sampleRate > 0) { | |||||
setSampleRate(settings::sampleRate); | |||||
} | |||||
else if (suggestedSampleRate > 0) { | |||||
setSampleRate(suggestedSampleRate); | |||||
} | |||||
else { | |||||
setSampleRate(FALLBACK_SAMPLE_RATE); | |||||
} | } | ||||
// Update expander pointers | // Update expander pointers | ||||
@@ -570,6 +570,21 @@ float Engine::getSampleRate() { | |||||
} | } | ||||
void Engine::setSampleRate(float sampleRate) { | |||||
if (sampleRate == internal->sampleRate) | |||||
return; | |||||
internal->sampleRate = sampleRate; | |||||
internal->sampleTime = 1.f / sampleRate; | |||||
// Trigger SampleRateChangeEvent | |||||
Module::SampleRateChangeEvent e; | |||||
e.sampleRate = internal->sampleRate; | |||||
e.sampleTime = internal->sampleTime; | |||||
for (Module* module : internal->modules) { | |||||
module->onSampleRateChange(e); | |||||
} | |||||
} | |||||
float Engine::getSampleTime() { | float Engine::getSampleTime() { | ||||
return internal->sampleTime; | return internal->sampleTime; | ||||
} | } | ||||
@@ -26,7 +26,7 @@ float cableTension = 0.5; | |||||
bool allowCursorLock = true; | bool allowCursorLock = true; | ||||
KnobMode knobMode = KNOB_MODE_LINEAR; | KnobMode knobMode = KNOB_MODE_LINEAR; | ||||
float knobLinearSensitivity = 0.001f; | float knobLinearSensitivity = 0.001f; | ||||
float sampleRate = 44100.0; | |||||
float sampleRate = 0; | |||||
int threadCount = 1; | int threadCount = 1; | ||||
bool tooltips = true; | bool tooltips = true; | ||||
bool cpuMeter = false; | bool cpuMeter = false; | ||||