diff --git a/res/LFO-1.svg b/res/LFO-1.svg
new file mode 100644
index 0000000..7509fc5
--- /dev/null
+++ b/res/LFO-1.svg
@@ -0,0 +1,482 @@
+
+
+
+
diff --git a/res/LFO-2.svg b/res/LFO-2.svg
new file mode 100644
index 0000000..a8b4329
--- /dev/null
+++ b/res/LFO-2.svg
@@ -0,0 +1,328 @@
+
+
+
+
diff --git a/res/SEQ3.svg b/res/SEQ3.svg
index 5b2c7cb..025d557 100644
--- a/res/SEQ3.svg
+++ b/res/SEQ3.svg
@@ -9,15 +9,15 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="87.444527mm"
- height="100.54166mm"
- viewBox="0 0 87.444527 100.54168"
+ width="330.49908"
+ height="380"
+ viewBox="0 0 87.444549 100.54166"
version="1.1"
- id="svg4541"
- sodipodi:docname="SEQ3.svg"
- inkscape:version="0.92.2 5c3e80d, 2017-08-06">
+ id="svg12553"
+ inkscape:version="0.92.2 5c3e80d, 2017-08-06"
+ sodipodi:docname="SEQ3.svg">
+ id="defs12547" />
+ inkscape:window-maximized="0">
+
+
+ id="metadata12550">
@@ -56,461 +63,481 @@
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
- transform="translate(36.687896,-107.67836)">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ transform="translate(-26.543497,-161.30655)">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/VCO-1.svg b/res/VCO-1.svg
new file mode 100644
index 0000000..bdba7dc
--- /dev/null
+++ b/res/VCO-1.svg
@@ -0,0 +1,466 @@
+
+
+
+
diff --git a/res/VCO-2.svg b/res/VCO-2.svg
new file mode 100644
index 0000000..c3e2536
--- /dev/null
+++ b/res/VCO-2.svg
@@ -0,0 +1,327 @@
+
+
+
+
diff --git a/res/VCO.svg b/res/VCO.svg
deleted file mode 100644
index 6846d25..0000000
--- a/res/VCO.svg
+++ /dev/null
@@ -1,452 +0,0 @@
-
-
-
-
diff --git a/src/ADSR.cpp b/src/ADSR.cpp
index b42a804..4b69b58 100644
--- a/src/ADSR.cpp
+++ b/src/ADSR.cpp
@@ -111,10 +111,10 @@ ADSRWidget::ADSRWidget() {
addChild(createScrew(Vec(15, 365)));
addChild(createScrew(Vec(box.size.x-30, 365)));
- addParam(createParam(Vec(62, 57), module, ADSR::ATTACK_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(62, 124), module, ADSR::DECAY_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(62, 191), module, ADSR::SUSTAIN_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(62, 257), module, ADSR::RELEASE_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(62, 57), module, ADSR::ATTACK_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(62, 124), module, ADSR::DECAY_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(62, 191), module, ADSR::SUSTAIN_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(62, 257), module, ADSR::RELEASE_PARAM, 0.0, 1.0, 0.5));
addInput(createInput(Vec(9, 63), module, ADSR::ATTACK_INPUT));
addInput(createInput(Vec(9, 129), module, ADSR::DECAY_INPUT));
diff --git a/src/Delay.cpp b/src/Delay.cpp
index 57398e1..2eb48e2 100644
--- a/src/Delay.cpp
+++ b/src/Delay.cpp
@@ -122,10 +122,10 @@ DelayWidget::DelayWidget() {
addChild(createScrew(Vec(15, 365)));
addChild(createScrew(Vec(box.size.x-30, 365)));
- addParam(createParam(Vec(67, 57), module, Delay::TIME_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(67, 123), module, Delay::FEEDBACK_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(67, 190), module, Delay::COLOR_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(67, 257), module, Delay::MIX_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(67, 57), module, Delay::TIME_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(67, 123), module, Delay::FEEDBACK_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(67, 190), module, Delay::COLOR_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(67, 257), module, Delay::MIX_PARAM, 0.0, 1.0, 0.5));
addInput(createInput(Vec(14, 63), module, Delay::TIME_INPUT));
addInput(createInput(Vec(14, 129), module, Delay::FEEDBACK_INPUT));
diff --git a/src/Fundamental.cpp b/src/Fundamental.cpp
index 7e2dce2..2a3ea76 100644
--- a/src/Fundamental.cpp
+++ b/src/Fundamental.cpp
@@ -8,9 +8,10 @@ void init(rack::Plugin *p) {
plugin->slug = "Fundamental";
plugin->name = "Fundamental";
plugin->homepageUrl = "https://github.com/VCVRack/Fundamental";
- createModel(plugin, "VCO", "VCO");
+ createModel(plugin, "VCO", "VCO-1");
createModel(plugin, "VCF", "VCF");
createModel(plugin, "VCA", "VCA");
+ createModel(plugin, "LFO", "LFO-1");
createModel(plugin, "Delay", "Delay");
createModel(plugin, "ADSR", "ADSR");
createModel(plugin, "VCMixer", "VC Mixer");
diff --git a/src/Fundamental.hpp b/src/Fundamental.hpp
index 08c89c5..476cc0c 100644
--- a/src/Fundamental.hpp
+++ b/src/Fundamental.hpp
@@ -22,6 +22,10 @@ struct VCAWidget : ModuleWidget {
VCAWidget();
};
+struct LFOWidget : ModuleWidget {
+ LFOWidget();
+};
+
struct DelayWidget : ModuleWidget {
DelayWidget();
};
diff --git a/src/LFO.cpp b/src/LFO.cpp
new file mode 100644
index 0000000..d5647cf
--- /dev/null
+++ b/src/LFO.cpp
@@ -0,0 +1,126 @@
+#include "Fundamental.hpp"
+
+
+struct LFO : Module {
+ enum ParamIds {
+ OFFSET_PARAM,
+ INVERT_PARAM,
+ FREQ_PARAM,
+ FM1_PARAM,
+ FM2_PARAM,
+ PW_PARAM,
+ PWM_PARAM,
+ NUM_PARAMS
+ };
+ enum InputIds {
+ FM1_INPUT,
+ FM2_INPUT,
+ RESET_INPUT,
+ PW_INPUT,
+ NUM_INPUTS
+ };
+ enum OutputIds {
+ SIN_OUTPUT,
+ TRI_OUTPUT,
+ SAW_OUTPUT,
+ SQR_OUTPUT,
+ NUM_OUTPUTS
+ };
+
+ float phase = 0.0;
+
+ float lights[1] = {};
+
+ LFO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
+ void step();
+};
+
+
+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;
+}
+
+
+LFOWidget::LFOWidget() {
+ LFO *module = new LFO();
+ setModule(module);
+ box.size = Vec(15*10, 380);
+
+ {
+ SVGPanel *panel = new SVGPanel();
+ panel->box.size = box.size;
+ panel->setBackground(SVG::load(assetPlugin(plugin, "res/LFO-1.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(15, 77), module, LFO::OFFSET_PARAM, 0.0, 1.0, 1.0));
+ addParam(createParam(Vec(119, 77), module, LFO::INVERT_PARAM, 0.0, 1.0, 1.0));
+
+ addParam(createParam(Vec(47, 61), module, LFO::FREQ_PARAM, -8.0, 6.0, -1.0));
+ addParam(createParam(Vec(23, 143), module, LFO::FM1_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(91, 143), module, LFO::PW_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(23, 208), module, LFO::FM2_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(91, 208), module, LFO::PWM_PARAM, 0.0, 1.0, 0.0));
+
+ addInput(createInput(Vec(11, 276), module, LFO::FM1_INPUT));
+ addInput(createInput(Vec(45, 276), module, LFO::FM2_INPUT));
+ addInput(createInput(Vec(80, 276), module, LFO::RESET_INPUT));
+ addInput(createInput(Vec(114, 276), module, LFO::PW_INPUT));
+
+ addOutput(createOutput(Vec(11, 320), module, LFO::SIN_OUTPUT));
+ addOutput(createOutput(Vec(45, 320), module, LFO::TRI_OUTPUT));
+ addOutput(createOutput(Vec(80, 320), module, LFO::SAW_OUTPUT));
+ addOutput(createOutput(Vec(114, 320), module, LFO::SQR_OUTPUT));
+
+ addChild(createValueLight>(Vec(99, 41), &module->lights[0]));
+}
diff --git a/src/SEQ3.cpp b/src/SEQ3.cpp
index 1aa1615..05d8e29 100644
--- a/src/SEQ3.cpp
+++ b/src/SEQ3.cpp
@@ -224,18 +224,18 @@ SEQ3Widget::SEQ3Widget() {
addChild(createScrew(Vec(15, 365)));
addChild(createScrew(Vec(box.size.x-30, 365)));
- addParam(createParam(Vec(17, 56), module, SEQ3::CLOCK_PARAM, -2.0, 6.0, 2.0));
+ addParam(createParam(Vec(18, 56), module, SEQ3::CLOCK_PARAM, -2.0, 6.0, 2.0));
addParam(createParam(Vec(60, 61-1), module, SEQ3::RUN_PARAM, 0.0, 1.0, 0.0));
addChild(createValueLight>(Vec(60+5, 61+4), &module->runningLight));
- addParam(createParam(Vec(98, 61-1), module, SEQ3::RESET_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(99, 61-1), module, SEQ3::RESET_PARAM, 0.0, 1.0, 0.0));
addChild(createValueLight>(Vec(98+5, 61+4), &module->resetLight));
addParam(createParam(Vec(132, 56), module, SEQ3::STEPS_PARAM, 1.0, 8.0, 8.0));
- addChild(createValueLight>(Vec(180.5, 65), &module->gatesLight));
- addChild(createValueLight>(Vec(218.5, 65), &module->rowLights[0]));
+ addChild(createValueLight>(Vec(180, 65), &module->gatesLight));
+ addChild(createValueLight>(Vec(219, 65), &module->rowLights[0]));
addChild(createValueLight>(Vec(257, 65), &module->rowLights[1]));
- addChild(createValueLight>(Vec(295.5, 65), &module->rowLights[2]));
+ addChild(createValueLight>(Vec(296, 65), &module->rowLights[2]));
- static const float portX[8] = {19, 57, 96, 134, 173, 211, 250, 288};
+ static const float portX[8] = {20, 58, 96, 135, 173, 212, 250, 289};
addInput(createInput(Vec(portX[0]-1, 99-1), module, SEQ3::CLOCK_INPUT));
addInput(createInput(Vec(portX[1]-1, 99-1), module, SEQ3::EXT_CLOCK_INPUT));
addInput(createInput(Vec(portX[2]-1, 99-1), module, SEQ3::RESET_INPUT));
diff --git a/src/VCA.cpp b/src/VCA.cpp
index f9bc912..484272d 100644
--- a/src/VCA.cpp
+++ b/src/VCA.cpp
@@ -60,8 +60,8 @@ VCAWidget::VCAWidget() {
addChild(createScrew(Vec(15, 365)));
addChild(createScrew(Vec(box.size.x-30, 365)));
- addParam(createParam(Vec(27, 57), module, VCA::LEVEL1_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(27, 222), module, VCA::LEVEL2_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(27, 57), module, VCA::LEVEL1_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(27, 222), module, VCA::LEVEL2_PARAM, 0.0, 1.0, 0.5));
addInput(createInput(Vec(11, 113), module, VCA::EXP1_INPUT));
addInput(createInput(Vec(54, 113), module, VCA::LIN1_INPUT));
diff --git a/src/VCF.cpp b/src/VCF.cpp
index 9318237..559864f 100644
--- a/src/VCF.cpp
+++ b/src/VCF.cpp
@@ -153,11 +153,11 @@ VCFWidget::VCFWidget() {
addChild(createScrew(Vec(15, 365)));
addChild(createScrew(Vec(box.size.x-30, 365)));
- addParam(createParam(Vec(33, 61), module, VCF::FREQ_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(12, 143), module, VCF::FINE_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(71, 143), module, VCF::RES_PARAM, 0.0, 1.0, 0.0));
- addParam(createParam(Vec(12, 208), module, VCF::FREQ_CV_PARAM, -1.0, 1.0, 0.0));
- addParam(createParam(Vec(71, 208), module, VCF::DRIVE_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(33, 61), module, VCF::FREQ_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(12, 143), module, VCF::FINE_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(71, 143), module, VCF::RES_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(12, 208), module, VCF::FREQ_CV_PARAM, -1.0, 1.0, 0.0));
+ addParam(createParam(Vec(71, 208), module, VCF::DRIVE_PARAM, 0.0, 1.0, 0.0));
addInput(createInput(Vec(10, 276), module, VCF::FREQ_INPUT));
addInput(createInput(Vec(48, 276), module, VCF::RES_INPUT));
diff --git a/src/VCMixer.cpp b/src/VCMixer.cpp
index 53ffb65..a0a40d1 100644
--- a/src/VCMixer.cpp
+++ b/src/VCMixer.cpp
@@ -63,10 +63,10 @@ VCMixerWidget::VCMixerWidget() {
addChild(createScrew(Vec(15, 365)));
addChild(createScrew(Vec(box.size.x-30, 365)));
- addParam(createParam(Vec(48, 55), module, VCMixer::MIX_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(57, 139), module, VCMixer::CH1_PARAM, 0.0, 1.0, 0.0));
- addParam(createParam(Vec(57, 219), module, VCMixer::CH2_PARAM, 0.0, 1.0, 0.0));
- addParam(createParam(Vec(57, 300), module, VCMixer::CH3_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(52, 58), module, VCMixer::MIX_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(57, 139), module, VCMixer::CH1_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(57, 219), module, VCMixer::CH2_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(57, 300), module, VCMixer::CH3_PARAM, 0.0, 1.0, 0.0));
addInput(createInput(Vec(16, 69), module, VCMixer::MIX_CV_INPUT));
addInput(createInput(Vec(22, 129), module, VCMixer::CH1_INPUT));
diff --git a/src/VCO.cpp b/src/VCO.cpp
index e75c1fe..56f7d97 100644
--- a/src/VCO.cpp
+++ b/src/VCO.cpp
@@ -17,14 +17,14 @@ struct VCO : Module {
FINE_PARAM,
FM_PARAM,
PW_PARAM,
- PW_CV_PARAM,
+ PWM_PARAM,
NUM_PARAMS
};
enum InputIds {
PITCH_INPUT,
FM_INPUT,
- PW_INPUT,
SYNC_INPUT,
+ PW_INPUT,
NUM_INPUTS
};
enum OutputIds {
@@ -90,7 +90,7 @@ void VCO::step() {
// Pulse width
const float pwMin = 0.01;
- float pw = clampf(params[PW_PARAM].value + params[PW_CV_PARAM].value * inputs[PW_INPUT].value / 10.0, pwMin, 1.0 - pwMin);
+ 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 = clampf(freq / gSampleRate, 1e-6, 0.5);
@@ -205,7 +205,7 @@ VCOWidget::VCOWidget() {
{
SVGPanel *panel = new SVGPanel();
panel->box.size = box.size;
- panel->setBackground(SVG::load(assetPlugin(plugin, "res/VCO.svg")));
+ panel->setBackground(SVG::load(assetPlugin(plugin, "res/VCO-1.svg")));
addChild(panel);
}
@@ -215,13 +215,13 @@ VCOWidget::VCOWidget() {
addChild(createScrew(Vec(box.size.x-30, 365)));
addParam(createParam(Vec(15, 77), module, VCO::MODE_PARAM, 0.0, 1.0, 1.0));
- addParam(createParam(Vec(120, 77), module, VCO::SYNC_PARAM, 0.0, 1.0, 1.0));
+ addParam(createParam(Vec(119, 77), module, VCO::SYNC_PARAM, 0.0, 1.0, 1.0));
- addParam(createParam(Vec(48, 61), module, VCO::FREQ_PARAM, -54.0, 54.0, 0.0));
- addParam(createParam(Vec(23, 143), module, VCO::FINE_PARAM, -1.0, 1.0, 0.0));
- addParam(createParam(Vec(91, 143), module, VCO::PW_PARAM, 0.0, 1.0, 0.5));
- addParam(createParam(Vec(23, 208), module, VCO::FM_PARAM, 0.0, 1.0, 0.0));
- addParam(createParam(Vec(91, 208), module, VCO::PW_CV_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(47, 61), module, VCO::FREQ_PARAM, -54.0, 54.0, 0.0));
+ addParam(createParam(Vec(23, 143), module, VCO::FINE_PARAM, -1.0, 1.0, 0.0));
+ addParam(createParam(Vec(91, 143), module, VCO::PW_PARAM, 0.0, 1.0, 0.5));
+ addParam(createParam(Vec(23, 208), module, VCO::FM_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(91, 208), module, VCO::PWM_PARAM, 0.0, 1.0, 0.0));
addInput(createInput(Vec(11, 276), module, VCO::PITCH_INPUT));
addInput(createInput(Vec(45, 276), module, VCO::FM_INPUT));