Browse Source

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.

tags/v1.0.0
Andrew Belt 6 years ago
parent
commit
da4110367a
16 changed files with 172 additions and 117 deletions
  1. +1
    -1
      include/app/CableWidget.hpp
  2. +0
    -69
      include/dsp/common.hpp
  3. +1
    -0
      include/dsp/resampler.hpp
  4. +78
    -0
      include/dsp/window.hpp
  5. +1
    -1
      include/engine/Cable.hpp
  6. +1
    -1
      include/engine/Module.hpp
  7. +18
    -0
      include/engine/ParamMap.hpp
  8. +1
    -0
      include/rack.hpp
  9. +24
    -17
      src/app/CableWidget.cpp
  10. +2
    -0
      src/app/ParamQuantity.cpp
  11. +23
    -12
      src/app/RackWidget.cpp
  12. +1
    -0
      src/audio.cpp
  13. +1
    -0
      src/dsp/minblep.cpp
  14. +16
    -12
      src/engine/Engine.cpp
  15. +1
    -1
      src/history.cpp
  16. +3
    -3
      src/window.cpp

+ 1
- 1
include/app/CableWidget.hpp View File

@@ -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<int, ModuleWidget*> &moduleWidgets);
void fromJson(json_t *rootJ);
void draw(const widget::DrawContext &ctx) override;
void drawPlugs(const widget::DrawContext &ctx);
};


+ 0
- 69
include/dsp/common.hpp View File

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


+ 1
- 0
include/dsp/resampler.hpp View File

@@ -3,6 +3,7 @@
#include "dsp/frame.hpp"
#include "dsp/ringbuffer.hpp"
#include "dsp/fir.hpp"
#include "dsp/window.hpp"
#include <assert.h>
#include <string.h>
#include <speex/speex_resampler.h>


+ 78
- 0
include/dsp/window.hpp View File

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

+ 1
- 1
include/engine/Cable.hpp View File

@@ -8,7 +8,7 @@ namespace engine {


struct Cable {
int id = 0;
int id = -1;
Module *outputModule = NULL;
int outputId;
Module *inputModule = NULL;


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

@@ -14,7 +14,7 @@ namespace engine {

struct Module {
/** Automatically generated by the engine. */
int id = 0;
int id = -1;
std::vector<Param> params;
std::vector<Output> outputs;
std::vector<Input> inputs;


+ 18
- 0
include/engine/ParamMap.hpp View File

@@ -0,0 +1,18 @@
#pragma once
#include "common.hpp"
#include "math.hpp"
#include <jansson.h>


namespace rack {
namespace engine {


struct ParamMap {
int moduleId;
int paramId;
};


} // namespace engine
} // namespace rack

+ 1
- 0
include/rack.hpp View File

@@ -88,6 +88,7 @@
#include "dsp/resampler.hpp"
#include "dsp/ringbuffer.hpp"
#include "dsp/vumeter.hpp"
#include "dsp/window.hpp"

namespace rack {



+ 24
- 17
src/app/CableWidget.cpp View File

@@ -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<int, ModuleWidget*> &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)) {


+ 2
- 0
src/app/ParamQuantity.cpp View File

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


+ 23
- 12
src/app/RackWidget.cpp View File

@@ -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<int, ModuleWidget*> 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);
}
}


+ 1
- 0
src/audio.cpp View File

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


+ 1
- 0
src/dsp/minblep.cpp View File

@@ -1,5 +1,6 @@
#include "dsp/minblep.hpp"
#include "dsp/fft.hpp"
#include "dsp/window.hpp"


namespace rack {


+ 16
- 12
src/engine/Engine.cpp View File

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


+ 1
- 1
src/history.cpp View File

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


+ 3
- 3
src/window.cpp View File

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


Loading…
Cancel
Save