From 0bf6cb76ef6822498ac29dbc7acf73a8d60921a3 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sat, 7 Oct 2017 07:28:18 -0400 Subject: [PATCH] Add LFO-2 --- res/LFO-2.svg | 6 +- src/Fundamental.cpp | 1 + src/Fundamental.hpp | 4 + src/LFO.cpp | 200 +++++++++++++++++++++++++++++++++----------- 4 files changed, 160 insertions(+), 51 deletions(-) diff --git a/res/LFO-2.svg b/res/LFO-2.svg index a8b4329..7885fda 100644 --- a/res/LFO-2.svg +++ b/res/LFO-2.svg @@ -25,9 +25,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1.979899" - inkscape:cx="2.0045011" - inkscape:cy="167.93165" + inkscape:zoom="11.2" + inkscape:cx="44.405311" + inkscape:cy="195.77864" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="false" diff --git a/src/Fundamental.cpp b/src/Fundamental.cpp index 2a3ea76..3570b1b 100644 --- a/src/Fundamental.cpp +++ b/src/Fundamental.cpp @@ -12,6 +12,7 @@ void init(rack::Plugin *p) { createModel(plugin, "VCF", "VCF"); createModel(plugin, "VCA", "VCA"); createModel(plugin, "LFO", "LFO-1"); + createModel(plugin, "LFO2", "LFO-2"); createModel(plugin, "Delay", "Delay"); createModel(plugin, "ADSR", "ADSR"); createModel(plugin, "VCMixer", "VC Mixer"); diff --git a/src/Fundamental.hpp b/src/Fundamental.hpp index 476cc0c..295e614 100644 --- a/src/Fundamental.hpp +++ b/src/Fundamental.hpp @@ -26,6 +26,10 @@ struct LFOWidget : ModuleWidget { LFOWidget(); }; +struct LFO2Widget : ModuleWidget { + LFO2Widget(); +}; + struct DelayWidget : ModuleWidget { DelayWidget(); }; diff --git a/src/LFO.cpp b/src/LFO.cpp index d5647cf..2d49a32 100644 --- a/src/LFO.cpp +++ b/src/LFO.cpp @@ -1,6 +1,61 @@ #include "Fundamental.hpp" +struct LFOGenerator { + float phase = 0.0; + float pw = 0.5; + float freq = 1.0; + float offset = 0.0; + float factor = 1.0; + void setPitch(float pitch) { + pitch = fminf(pitch, 8.0); + freq = powf(2.0, pitch); + } + void setPulseWidth(float pw_) { + const float pwMin = 0.01; + pw = clampf(pw_, pwMin, 1.0 - pwMin); + } + void setOffset(bool offset_) { + offset = offset_ ? 1.0 : 0.0; + } + void setInvert(bool invert) { + factor = invert ? -1.0 : 1.0; + } + void step(float dt) { + float deltaPhase = fminf(freq * dt, 0.5); + phase += deltaPhase; + if (phase >= 1.0) + phase -= 1.0; + } + float sin() { + float sin = sinf(2*M_PI * phase); + return factor * sin + offset; + } + float tri() { + float tri; + if (phase < 0.25) + tri = 4.0*phase; + else if (phase < 0.75) + tri = 2.0 - 4.0*phase; + else + tri = -4.0 + 4.0*phase; + return factor * tri + offset; + } + float saw() { + float saw; + if (phase < 0.5) + saw = 2.0*phase; + else + saw = -2.0 + 2.0*phase; + return factor * saw + offset; + } + float sqr() { + float sqr = phase < pw ? 1.0 : -1.0; + return factor * sqr + offset; + } +}; + + struct LFO : Module { enum ParamIds { OFFSET_PARAM, @@ -27,8 +82,7 @@ struct LFO : Module { NUM_OUTPUTS }; - float phase = 0.0; - + LFOGenerator generator; float lights[1] = {}; LFO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} @@ -37,52 +91,18 @@ struct LFO : Module { void LFO::step() { - // Compute frequency - float pitch = params[FREQ_PARAM].value; - pitch += params[FM1_PARAM].value * inputs[FM1_INPUT].value; - pitch += params[FM2_PARAM].value * inputs[FM2_INPUT].value; - pitch = fminf(pitch, 8.0); - float freq = powf(2.0, pitch); - - // Pulse width - const float pwMin = 0.01; - float pw = clampf(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.0, pwMin, 1.0 - pwMin); - - // Advance phase - float deltaPhase = fminf(freq / gSampleRate, 0.5); - phase += deltaPhase; - if (phase >= 1.0) - phase -= 1.0; - - float offset = params[OFFSET_PARAM].value > 0.0 ? 5.0 : 0.0; - float factor = params[INVERT_PARAM].value > 0.0 ? 5.0 : -5.0; - - // Outputs - float sin = sinf(2*M_PI * phase); - - float tri; - if (phase < 0.25) - tri = 4.0*phase; - else if (phase < 0.75) - tri = 2.0 - 4.0*phase; - else - tri = -4.0 + 4.0*phase; - - float saw; - if (phase < 0.5) - saw = 2.0*phase; - else - saw = -2.0 + 2.0*phase; - - float sqr = phase < pw ? 1.0 : -1.0; - - outputs[SIN_OUTPUT].value = factor * sin + offset; - outputs[TRI_OUTPUT].value = factor * tri + offset; - outputs[SAW_OUTPUT].value = factor * saw + offset; - outputs[SQR_OUTPUT].value = factor * sqr + offset; - - // Lights - lights[0] = -1.0 + 2.0*phase; + generator.setPitch(params[FREQ_PARAM].value + params[FM1_PARAM].value * inputs[FM1_INPUT].value + params[FM2_PARAM].value * inputs[FM2_INPUT].value); + generator.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.0); + generator.setOffset(params[OFFSET_PARAM].value > 0.0); + generator.setInvert(params[INVERT_PARAM].value <= 0.0); + generator.step(1.0 / gSampleRate); + + outputs[SIN_OUTPUT].value = 5.0 * generator.sin(); + outputs[TRI_OUTPUT].value = 5.0 * generator.tri(); + outputs[SAW_OUTPUT].value = 5.0 * generator.saw(); + outputs[SQR_OUTPUT].value = 5.0 * generator.sqr(); + + lights[0] = -1.0 + 2.0*generator.phase; } @@ -124,3 +144,87 @@ LFOWidget::LFOWidget() { addChild(createValueLight>(Vec(99, 41), &module->lights[0])); } + + + +struct LFO2 : Module { + enum ParamIds { + OFFSET_PARAM, + INVERT_PARAM, + FREQ_PARAM, + WAVE_PARAM, + FM_PARAM, + NUM_PARAMS + }; + enum InputIds { + FM_INPUT, + RESET_INPUT, + WAVE_INPUT, + NUM_INPUTS + }; + enum OutputIds { + INTERP_OUTPUT, + NUM_OUTPUTS + }; + + LFOGenerator generator; + float lights[1] = {}; + + LFO2() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} + void step(); +}; + + +void LFO2::step() { + generator.setPitch(params[FREQ_PARAM].value + params[FM_PARAM].value * inputs[FM_INPUT].value); + generator.setOffset(params[OFFSET_PARAM].value > 0.0); + generator.setInvert(params[INVERT_PARAM].value <= 0.0); + generator.step(1.0 / gSampleRate); + + float wave = params[WAVE_PARAM].value + inputs[WAVE_INPUT].value; + wave = clampf(wave, 0.0, 3.0); + float interp; + if (wave < 1.0) + interp = crossf(generator.sin(), generator.tri(), wave); + else if (wave < 2.0) + interp = crossf(generator.tri(), generator.saw(), wave - 1.0); + else + interp = crossf(generator.saw(), generator.sqr(), wave - 2.0); + outputs[INTERP_OUTPUT].value = 5.0 * interp; + + lights[0] = -1.0 + 2.0*generator.phase; +} + + +LFO2Widget::LFO2Widget() { + LFO2 *module = new LFO2(); + setModule(module); + box.size = Vec(15*6, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/LFO-2.svg"))); + addChild(panel); + } + + addChild(createScrew(Vec(15, 0))); + addChild(createScrew(Vec(box.size.x-30, 0))); + addChild(createScrew(Vec(15, 365))); + addChild(createScrew(Vec(box.size.x-30, 365))); + + addParam(createParam(Vec(62, 150), module, LFO2::OFFSET_PARAM, 0.0, 1.0, 1.0)); + addParam(createParam(Vec(62, 215), module, LFO2::INVERT_PARAM, 0.0, 1.0, 1.0)); + + addParam(createParam(Vec(18, 60), module, LFO2::FREQ_PARAM, -8.0, 6.0, -1.0)); + addParam(createParam(Vec(11, 142), module, LFO2::WAVE_PARAM, 0.0, 3.0, 0.0)); + addParam(createParam(Vec(11, 207), module, LFO2::FM_PARAM, 0.0, 1.0, 0.5)); + + addInput(createInput(Vec(11, 276), module, LFO2::FM_INPUT)); + addInput(createInput(Vec(54, 276), module, LFO2::RESET_INPUT)); + addInput(createInput(Vec(11, 319), module, LFO2::WAVE_INPUT)); + + addOutput(createOutput(Vec(54, 319), module, LFO2::INTERP_OUTPUT)); + + addChild(createValueLight>(Vec(68, 41), &module->lights[0])); +}