From da4110367a41177b08d380dfe47e4c29c0e3f3c1 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Wed, 6 Feb 2019 22:26:38 -0500 Subject: [PATCH] Move DSP window functions to window.hpp. Use 0-indexed module/cable IDs instead of 1-indexed. Unserialize module/cable IDs as they are in the patch file. --- include/app/CableWidget.hpp | 2 +- include/dsp/common.hpp | 69 -------------------------------- include/dsp/resampler.hpp | 1 + include/dsp/window.hpp | 78 +++++++++++++++++++++++++++++++++++++ include/engine/Cable.hpp | 2 +- include/engine/Module.hpp | 2 +- include/engine/ParamMap.hpp | 18 +++++++++ include/rack.hpp | 1 + src/app/CableWidget.cpp | 41 +++++++++++-------- src/app/ParamQuantity.cpp | 2 + src/app/RackWidget.cpp | 35 +++++++++++------ src/audio.cpp | 1 + src/dsp/minblep.cpp | 1 + src/engine/Engine.cpp | 28 +++++++------ src/history.cpp | 2 +- src/window.cpp | 6 +-- 16 files changed, 172 insertions(+), 117 deletions(-) create mode 100644 include/dsp/window.hpp create mode 100644 include/engine/ParamMap.hpp diff --git a/include/app/CableWidget.hpp b/include/app/CableWidget.hpp index 2bc4324c..fb54eead 100644 --- a/include/app/CableWidget.hpp +++ b/include/app/CableWidget.hpp @@ -27,7 +27,7 @@ struct CableWidget : widget::OpaqueWidget { math::Vec getOutputPos(); math::Vec getInputPos(); json_t *toJson(); - void fromJson(json_t *rootJ, const std::map &moduleWidgets); + void fromJson(json_t *rootJ); void draw(const widget::DrawContext &ctx) override; void drawPlugs(const widget::DrawContext &ctx); }; diff --git a/include/dsp/common.hpp b/include/dsp/common.hpp index 5d69d450..dc447f85 100644 --- a/include/dsp/common.hpp +++ b/include/dsp/common.hpp @@ -23,75 +23,6 @@ inline float sinc(float x) { return std::sin(x) / x; } -// Window functions - -/** Hann window function -p: proportion from [0, 1], usually `i / (len - 1)` -https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows -*/ -inline float hann(float p) { - return 0.5f * (1.f - std::cos(2*M_PI * p)); -} - -/** Applies the Hann window to a signal `x` */ -inline void hannWindow(float *x, int len) { - for (int i = 0; i < len; i++) { - x[i] *= hann((float) i / (len - 1)); - } -} - -/** Blackman window function -https://en.wikipedia.org/wiki/Window_function#Blackman_window -A typical alpha value is 0.16. -*/ -inline float blackman(float alpha, float p) { - return - + (1 - alpha) / 2.f - - 1 / 2.f * std::cos(2*M_PI * p) - + alpha / 2.f * std::cos(4*M_PI * p); -} - -inline void blackmanWindow(float alpha, float *x, int len) { - for (int i = 0; i < len; i++) { - x[i] *= blackman(alpha, (float) i / (len - 1)); - } -} - - -/** Blackman-Nuttall window function -https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Nuttall_window -*/ -inline float blackmanNuttall(float p) { - return - + 0.3635819f - - 0.4891775f * std::cos(2*M_PI * p) - + 0.1365995f * std::cos(4*M_PI * p) - - 0.0106411f * std::cos(6*M_PI * p); -} - -inline void blackmanNuttallWindow(float *x, int len) { - for (int i = 0; i < len; i++) { - x[i] *= blackmanNuttall((float) i / (len - 1)); - } -} - -/** Blackman-Harris window function -https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Harris_window -*/ -inline float blackmanHarris(float p) { - return - + 0.35875f - - 0.48829f * std::cos(2*M_PI * p) - + 0.14128f * std::cos(4*M_PI * p) - - 0.01168f * std::cos(6*M_PI * p); -} - -inline void blackmanHarrisWindow(float *x, int len) { - for (int i = 0; i < len; i++) { - x[i] *= blackmanHarris((float) i / (len - 1)); - } -} - // Conversion functions inline float amplitudeToDb(float amp) { diff --git a/include/dsp/resampler.hpp b/include/dsp/resampler.hpp index 8d5d1665..fd66417a 100644 --- a/include/dsp/resampler.hpp +++ b/include/dsp/resampler.hpp @@ -3,6 +3,7 @@ #include "dsp/frame.hpp" #include "dsp/ringbuffer.hpp" #include "dsp/fir.hpp" +#include "dsp/window.hpp" #include #include #include diff --git a/include/dsp/window.hpp b/include/dsp/window.hpp new file mode 100644 index 00000000..f53dfd20 --- /dev/null +++ b/include/dsp/window.hpp @@ -0,0 +1,78 @@ +#pragma once +#include "math.hpp" + + +namespace rack { +namespace dsp { + + +/** Hann window function +p: proportion from [0, 1], usually `i / (len - 1)` +https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows +*/ +inline float hann(float p) { + return 0.5f * (1.f - std::cos(2*M_PI * p)); +} + +/** Applies the Hann window to a signal `x` */ +inline void hannWindow(float *x, int len) { + for (int i = 0; i < len; i++) { + x[i] *= hann((float) i / (len - 1)); + } +} + +/** Blackman window function +https://en.wikipedia.org/wiki/Window_function#Blackman_window +A typical alpha value is 0.16. +*/ +inline float blackman(float alpha, float p) { + return + + (1 - alpha) / 2.f + - 1 / 2.f * std::cos(2*M_PI * p) + + alpha / 2.f * std::cos(4*M_PI * p); +} + +inline void blackmanWindow(float alpha, float *x, int len) { + for (int i = 0; i < len; i++) { + x[i] *= blackman(alpha, (float) i / (len - 1)); + } +} + + +/** Blackman-Nuttall window function +https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Nuttall_window +*/ +inline float blackmanNuttall(float p) { + return + + 0.3635819f + - 0.4891775f * std::cos(2*M_PI * p) + + 0.1365995f * std::cos(4*M_PI * p) + - 0.0106411f * std::cos(6*M_PI * p); +} + +inline void blackmanNuttallWindow(float *x, int len) { + for (int i = 0; i < len; i++) { + x[i] *= blackmanNuttall((float) i / (len - 1)); + } +} + +/** Blackman-Harris window function +https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Harris_window +*/ +inline float blackmanHarris(float p) { + return + + 0.35875f + - 0.48829f * std::cos(2*M_PI * p) + + 0.14128f * std::cos(4*M_PI * p) + - 0.01168f * std::cos(6*M_PI * p); +} + +inline void blackmanHarrisWindow(float *x, int len) { + for (int i = 0; i < len; i++) { + x[i] *= blackmanHarris((float) i / (len - 1)); + } +} + + +} // namespace dsp +} // namespace rack diff --git a/include/engine/Cable.hpp b/include/engine/Cable.hpp index 53c2f173..c6bb099d 100644 --- a/include/engine/Cable.hpp +++ b/include/engine/Cable.hpp @@ -8,7 +8,7 @@ namespace engine { struct Cable { - int id = 0; + int id = -1; Module *outputModule = NULL; int outputId; Module *inputModule = NULL; diff --git a/include/engine/Module.hpp b/include/engine/Module.hpp index aedf2b2c..905a975b 100644 --- a/include/engine/Module.hpp +++ b/include/engine/Module.hpp @@ -14,7 +14,7 @@ namespace engine { struct Module { /** Automatically generated by the engine. */ - int id = 0; + int id = -1; std::vector params; std::vector outputs; std::vector inputs; diff --git a/include/engine/ParamMap.hpp b/include/engine/ParamMap.hpp new file mode 100644 index 00000000..44c61c88 --- /dev/null +++ b/include/engine/ParamMap.hpp @@ -0,0 +1,18 @@ +#pragma once +#include "common.hpp" +#include "math.hpp" +#include + + +namespace rack { +namespace engine { + + +struct ParamMap { + int moduleId; + int paramId; +}; + + +} // namespace engine +} // namespace rack diff --git a/include/rack.hpp b/include/rack.hpp index c0d388da..3d9a0ab7 100644 --- a/include/rack.hpp +++ b/include/rack.hpp @@ -88,6 +88,7 @@ #include "dsp/resampler.hpp" #include "dsp/ringbuffer.hpp" #include "dsp/vumeter.hpp" +#include "dsp/window.hpp" namespace rack { diff --git a/src/app/CableWidget.cpp b/src/app/CableWidget.cpp index fa00d815..b053cf05 100644 --- a/src/app/CableWidget.cpp +++ b/src/app/CableWidget.cpp @@ -146,9 +146,6 @@ json_t *CableWidget::toJson() { assert(isComplete()); json_t *rootJ = json_object(); - // This is just here for fun. It is not used in fromJson(), since cableIds are not preserved across multiple launches of Rack. - json_object_set_new(rootJ, "id", json_integer(cable->id)); - json_object_set_new(rootJ, "outputModuleId", json_integer(cable->outputModule->id)); json_object_set_new(rootJ, "outputId", json_integer(cable->outputId)); json_object_set_new(rootJ, "inputModuleId", json_integer(cable->inputModule->id)); @@ -160,20 +157,30 @@ json_t *CableWidget::toJson() { return rootJ; } -void CableWidget::fromJson(json_t *rootJ, const std::map &moduleWidgets) { - int outputModuleId = json_integer_value(json_object_get(rootJ, "outputModuleId")); - int outputId = json_integer_value(json_object_get(rootJ, "outputId")); - int inputModuleId = json_integer_value(json_object_get(rootJ, "inputModuleId")); - int inputId = json_integer_value(json_object_get(rootJ, "inputId")); - - // Get module widgets - auto outputModuleIt = moduleWidgets.find(outputModuleId); - auto inputModuleIt = moduleWidgets.find(inputModuleId); - if (outputModuleIt == moduleWidgets.end() || inputModuleIt == moduleWidgets.end()) - return; - - ModuleWidget *outputModule = outputModuleIt->second; - ModuleWidget *inputModule = inputModuleIt->second; +void CableWidget::fromJson(json_t *rootJ) { + // outputModuleId + json_t *outputModuleIdJ = json_object_get(rootJ, "outputModuleId"); + if (!outputModuleIdJ) return; + int outputModuleId = json_integer_value(outputModuleIdJ); + ModuleWidget *outputModule = APP->scene->rackWidget->getModule(outputModuleId); + if (!outputModule) return; + + // inputModuleId + json_t *inputModuleIdJ = json_object_get(rootJ, "inputModuleId"); + if (!inputModuleIdJ) return; + int inputModuleId = json_integer_value(inputModuleIdJ); + ModuleWidget *inputModule = APP->scene->rackWidget->getModule(inputModuleId); + if (!inputModule) return; + + // outputId + json_t *outputIdJ = json_object_get(rootJ, "outputId"); + if (!outputIdJ) return; + int outputId = json_integer_value(outputIdJ); + + // inputId + json_t *inputIdJ = json_object_get(rootJ, "inputId"); + if (!inputIdJ) return; + int inputId = json_integer_value(inputIdJ); // Set ports if (APP->patch->isLegacy(1)) { diff --git a/src/app/ParamQuantity.cpp b/src/app/ParamQuantity.cpp index b86ff89e..a59f1661 100644 --- a/src/app/ParamQuantity.cpp +++ b/src/app/ParamQuantity.cpp @@ -26,6 +26,8 @@ float ParamQuantity::getSmoothValue() { void ParamQuantity::setValue(float value) { if (!module) return; + if (!std::isfinite(value)) + return; // This setter clamps the value getParam()->setValue(value); } diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 1347dd16..fd383425 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -229,7 +229,13 @@ json_t *RackWidget::toJson() { if (!cw->isComplete()) continue; - json_array_append_new(cablesJ, cw->toJson()); + json_t *cableJ = cw->toJson(); + { + // id + json_object_set_new(rootJ, "id", json_integer(cw->cable->id)); + } + json_array_append_new(cablesJ, cableJ); + } json_object_set_new(rootJ, "cables", cablesJ); @@ -241,18 +247,21 @@ void RackWidget::fromJson(json_t *rootJ) { json_t *modulesJ = json_object_get(rootJ, "modules"); if (!modulesJ) return; - std::map moduleWidgets; size_t moduleIndex; json_t *moduleJ; json_array_foreach(modulesJ, moduleIndex, moduleJ) { ModuleWidget *moduleWidget = moduleFromJson(moduleJ); if (moduleWidget) { + // Before 1.0, the module ID was the index in the "modules" array + if (APP->patch->isLegacy(2)) { + moduleWidget->module->id = moduleIndex; + } // id json_t *idJ = json_object_get(moduleJ, "id"); - int id = 0; if (idJ) - id = json_integer_value(idJ); + moduleWidget->module->id = json_integer_value(idJ); + // pos json_t *posJ = json_object_get(moduleJ, "pos"); double x, y; @@ -266,13 +275,6 @@ void RackWidget::fromJson(json_t *rootJ) { moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE); } - if (APP->patch->isLegacy(2)) { - // Before 1.0, the module ID was the index in the "modules" array - moduleWidgets[moduleIndex] = moduleWidget; - } - else { - moduleWidgets[id] = moduleWidget; - } addModule(moduleWidget); } else { @@ -295,11 +297,20 @@ void RackWidget::fromJson(json_t *rootJ) { json_array_foreach(cablesJ, cableIndex, cableJ) { // Create a unserialize cable CableWidget *cw = new CableWidget; - cw->fromJson(cableJ, moduleWidgets); + cw->fromJson(cableJ); if (!cw->isComplete()) { delete cw; continue; } + + // Before 1.0, cables IDs were not used, so just use the index of the "cables" array. + if (APP->patch->isLegacy(2)) { + cw->cable->id = cableIndex; + } + // id + json_t *idJ = json_object_get(cableJ, "id"); + if (idJ) + cw->cable->id = json_integer_value(idJ); addCable(cw); } } diff --git a/src/audio.cpp b/src/audio.cpp index 901dcfa9..04f6a60f 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -211,6 +211,7 @@ static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrame // Exploit the stream time to run code on startup of the audio thread if (streamTime == 0.0) { system::setThreadName("Audio"); + system::setThreadRealTime(); } audioIO->processStream((const float *) inputBuffer, (float *) outputBuffer, nFrames); return 0; diff --git a/src/dsp/minblep.cpp b/src/dsp/minblep.cpp index 6a7b47ca..7be6f209 100644 --- a/src/dsp/minblep.cpp +++ b/src/dsp/minblep.cpp @@ -1,5 +1,6 @@ #include "dsp/minblep.hpp" #include "dsp/fft.hpp" +#include "dsp/window.hpp" namespace rack { diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 16116136..85f6b1cf 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -100,8 +100,6 @@ struct EngineWorker { void start() { thread = std::thread([&] { - system::setThreadName("Engine worker"); - system::setThreadRealTime(); run(); }); } @@ -115,6 +113,8 @@ struct EngineWorker { } void run() { + system::setThreadName("Engine worker"); + system::setThreadRealTime(); while (running) { step(); } @@ -134,8 +134,8 @@ struct Engine::Internal { float sampleTime; float sampleRateRequested; - int nextModuleId = 1; - int nextCableId = 1; + int nextModuleId = 0; + int nextCableId = 0; // Parameter smoothing Module *smoothModule = NULL; @@ -209,13 +209,13 @@ static void Engine_setWorkerCount(Engine *engine, int workerCount) { } } -static void Engine_stepModules(Engine *engine, int id) { +static void Engine_stepModules(Engine *engine, int threadId) { Engine::Internal *internal = engine->internal; int threadCount = internal->threadCount; int modulesLen = internal->modules.size(); - for (int i = id; i < modulesLen; i += threadCount) { + for (int i = threadId; i < modulesLen; i += threadCount) { Module *module = internal->modules[i]; if (!module->bypass) { // Step module @@ -389,17 +389,19 @@ void Engine::addModule(Module *module) { auto it = std::find(internal->modules.begin(), internal->modules.end(), module); assert(it == internal->modules.end()); // Set ID - if (module->id == 0) { + if (module->id < 0) { // Automatically assign ID module->id = internal->nextModuleId++; } else { // Manual ID - assert(module->id < internal->nextModuleId); // Check that the ID is not already taken for (Module *m : internal->modules) { assert(module->id != m->id); } + if (module->id >= internal->nextModuleId) { + internal->nextModuleId = module->id + 1; + } } // Add module internal->modules.push_back(module); @@ -424,7 +426,7 @@ void Engine::removeModule(Module *module) { // Remove the module internal->modules.erase(it); // Remove id - module->id = 0; + module->id = -1; } void Engine::resetModule(Module *module) { @@ -493,17 +495,19 @@ void Engine::addCable(Cable *cable) { assert(!(cable2->inputModule == cable->inputModule && cable2->inputId == cable->inputId)); } // Set ID - if (cable->id == 0) { + if (cable->id < 0) { // Automatically assign ID cable->id = internal->nextCableId++; } else { // Manual ID - assert(cable->id < internal->nextCableId); // Check that the ID is not already taken for (Cable *w : internal->cables) { assert(cable->id != w->id); } + if (cable->id >= internal->nextCableId) { + internal->nextCableId = cable->id + 1; + } } // Add the cable internal->cables.push_back(cable); @@ -524,7 +528,7 @@ void Engine::removeCable(Cable *cable) { internal->cables.erase(it); Engine_updateConnected(this); // Remove ID - cable->id = 0; + cable->id = -1; } void Engine::setParam(Module *module, int paramId, float value) { diff --git a/src/history.cpp b/src/history.cpp index 2cb7ffad..23571722 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -124,7 +124,7 @@ void ParamChange::redo() { void CableAdd::setCable(app::CableWidget *cw) { assert(cw->cable); - assert(cw->cable->id > 0); + assert(cw->cable->id >= 0); cableId = cw->cable->id; assert(cw->cable->outputModule); outputModuleId = cw->cable->outputModule->id; diff --git a/src/window.cpp b/src/window.cpp index 8e7a67a4..e084ca22 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -209,9 +209,9 @@ Window::Window() { exit(1); } - float pixelRatio; - glfwGetWindowContentScale(win, &pixelRatio, NULL); - INFO("Pixel ratio: %f", pixelRatio); + float contentScale; + glfwGetWindowContentScale(win, &contentScale, NULL); + INFO("Window content scale: %f", contentScale); glfwSetWindowSizeLimits(win, 800, 600, GLFW_DONT_CARE, GLFW_DONT_CARE); if (settings.windowSize.isZero()) {