commit 8828129f2e4802e8c2ad7eea817193e629f71c2e
parent c95cda370dfb7918aaf63e814463679587da9973
Author: Matt Demanett <matt@demanett.net>
Date: Wed, 21 Mar 2018 02:13:35 -0400
XCO implementation.
Diffstat:
7 files changed, 218 insertions(+), 79 deletions(-)
diff --git a/res-src/VCO-src.svg b/res-src/VCO-src.svg
@@ -236,7 +236,7 @@
<use id="FINE_PARAM" xlink:href="#knob-smallest" transform="translate(13 0)" />
<!-- <rect width="90" height="10" fill="#0f0" transform="translate(0 17)" /> -->
</g>
- <use xlink:href="#knobguide-centertick" transform="translate(21 140)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(21 139)" />
<g transform="translate(90 156.5)">
<!-- <polyline points="0,3.2 70,3.2" stroke="#0f0" stroke-width="1" fill="none" /> -->
@@ -268,11 +268,11 @@
<!-- <rect width="90" height="10" fill="#0f0" transform="translate(0 26)" /> -->
<g transform="translate(52 1)">
<use id="FM_TYPE_PARAM" xlink:href="#button-small" transform="translate(30 7.5)" />
- <g transform="translate(0 3)">
+ <g transform="translate(0 2)">
<use id="FM_EXP_LIGHT" xlink:href="#light-small" transform="translate(0 0)" />
<text font-size="6pt" letter-spacing="2px" transform="translate(9 6.2)">EXP</text>
</g>
- <g transform="translate(0 14.3)">
+ <g transform="translate(0 15.3)">
<use id="FM_LIN_LIGHT" xlink:href="#light-small" transform="translate(0 0)" />
<text font-size="6pt" letter-spacing="2px" transform="translate(9 6.2)">LIN</text>
</g>
diff --git a/res-src/XCO-src.svg b/res-src/XCO-src.svg
@@ -31,14 +31,6 @@
</g>
</symbol>
- <symbol id="knob" viewBox="0 0 38px 38px">
- <g transform="translate(19 19)">
- <polyline points="-5,0 5,0" stroke-width="1" stroke="#00f" />
- <polyline points="0,-5 0,5" stroke-width="1" stroke="#00f" />
- <circle cx="0" cy="0" r="18" stroke-width="1" stroke="#00f" fill="none" />
- </g>
- </symbol>
-
<symbol id="knob-medium" viewBox="0 0 26px 26px">
<g transform="translate(13 13)">
<polyline points="-3,0 3,0" stroke-width="1" stroke="#00f" />
@@ -249,32 +241,30 @@
<rect width="3.0" height="3" fill="#ddd" transform="translate(24 -5)" />
</g>
- <g transform="translate(10 30)">
- <g transform="translate(10 0)">
- <!-- <rect width="108" height="98" fill="none" stroke="#0f0" /> -->
- <!-- <polyline points="0,54 54,54" stroke="#0f0" stroke-width="1" fill="none" /> -->
- <!-- <polyline points="54,54 54,354" stroke="#0f0" stroke-width="1" fill="none" /> -->
- <use id="FREQUENCY_PARAM" xlink:href="#knob-large" transform="translate(20 20)" />
- </g>
+ <g transform="translate(20 25)">
+ <!-- <rect width="108" height="98" fill="none" stroke="#0f0" /> -->
+ <!-- <polyline points="0,54 54,54" stroke="#0f0" stroke-width="1" fill="none" /> -->
+ <!-- <polyline points="54,54 54,354" stroke="#0f0" stroke-width="1" fill="none" /> -->
+ <use id="FREQUENCY_PARAM" xlink:href="#knob-large" transform="translate(20 20)" />
</g>
- <use xlink:href="#knobguide-frequency" transform="translate(20 30)" />
+ <use xlink:href="#knobguide-frequency" transform="translate(20 25)" />
- <text font-size="6pt" letter-spacing="1px" transform="translate(29 142)">0V = C4 = 261.63HZ</text>
+ <text font-size="6pt" letter-spacing="1px" transform="translate(29 136)">0V = C4 = 261.63HZ</text>
<!-- <rect width="90" height="10" fill="#0f0" transform="translate(0 143)" /> -->
- <g transform="translate(45.5 160)">
+ <g transform="translate(45.5 156)">
<!-- <polyline points="0,8 70,8" stroke="#0f0" stroke-width="1" fill="none" /> -->
- <text font-size="8pt" letter-spacing="2px" transform="translate(5.7 24) rotate(270)">FINE</text>
+ <text font-size="8pt" letter-spacing="2px" transform="translate(5.7 22) rotate(270)">FINE</text>
<use id="FINE_PARAM" xlink:href="#knob-smallest" transform="translate(20 0)" />
<!-- <rect width="90" height="10" fill="#0f0" transform="translate(0 17)" /> -->
</g>
- <use xlink:href="#knobguide-centertick" transform="translate(53.7 148)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(53.7 144)" />
- <g transform="translate(45.5 195)">
+ <g transform="translate(50 193)">
<!-- <polyline points="0,3.2 70,3.2" stroke="#0f0" stroke-width="1" fill="none" /> -->
+ <use id="SLOW_PARAM" xlink:href="#button-small" transform="translate(40 -1.3)" />
<use id="SLOW_LIGHT" xlink:href="#light-small" transform="translate(0 0)" />
- <text font-size="7pt" letter-spacing="2px" transform="translate(11 6.5)">SLOW</text>
- <use id="SLOW_PARAM" xlink:href="#button-small" transform="translate(48 -1.5)" />
+ <text font-size="6pt" letter-spacing="2px" transform="translate(9 6.1)">SLOW</text>
<!-- <rect width="90" height="10" fill="#0f0" transform="translate(0 7)" /> -->
</g>
@@ -293,22 +283,22 @@
<use id="FM_INPUT" xlink:href="#input" transform="translate(3 5)" />
<text font-size="6pt" letter-spacing="1px" transform="translate(9 40)">FM</text>
</g>
- <g transform="translate(40 11.5)">
- <g transform="translate(0 0)">
+ <g transform="translate(42 11.5)">
+ <use id="FM_TYPE_PARAM" xlink:href="#button-small" transform="translate(30 7.5)" />
+ <g transform="translate(0 2)">
<use id="FM_EXP_LIGHT" xlink:href="#light-small" transform="translate(0 0)" />
- <text font-size="7pt" letter-spacing="2px" transform="translate(11 6.7)">EXP</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(9 6.2)">EXP</text>
</g>
- <g transform="translate(0 17)">
+ <g transform="translate(0 15.3)">
<use id="FM_LIN_LIGHT" xlink:href="#light-small" transform="translate(0 0)" />
- <text font-size="7pt" letter-spacing="2px" transform="translate(11 6.7)">LIN</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(9 6.2)">LIN</text>
</g>
- <use id="FM_TYPE_PARAM" xlink:href="#button-small" transform="translate(38 7.5)" />
</g>
</g>
</g>
<use xlink:href="#knobguide-fm" transform="translate(51.5 209.5)" />
- <rect width="190" height="47" rx="5" fill="#bbb" transform="translate(100 313)" />
+ <rect width="191" height="47" rx="5" fill="#bbb" transform="translate(99 313)" />
<g transform="translate(140 30)">
<rect width="30" height="330" rx="5" fill="#fafafa" />
@@ -316,11 +306,11 @@
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 90)" /> -->
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 177)" /> -->
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 267)" /> -->
- <text font-size="6pt" letter-spacing="2px" transform="translate(5 15)">SQR</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(5.2 15)">SQR</text>
<g transform="translate(3 30)">
- <use id="SQUARE_PWM_PARAM" xlink:href="#knob-smallest" transform="translate(4 0)" />
- <text font-size="6pt" letter-spacing="2px" transform="translate(1 30)">PWM</text>
- <use id="SQUARE_PWM_INPUT" xlink:href="#input" transform="translate(0 35)" />
+ <use id="SQUARE_PW_PARAM" xlink:href="#knob-smallest" transform="translate(4 0)" />
+ <text font-size="6pt" letter-spacing="2px" transform="translate(5 30)">PW</text>
+ <use id="SQUARE_PW_INPUT" xlink:href="#input" transform="translate(0 35)" />
</g>
<g transform="translate(3 118)">
<use id="SQUARE_PHASE_PARAM" xlink:href="#knob-smallest" transform="translate(4 0)" />
@@ -329,12 +319,12 @@
</g>
<g transform="translate(3 207)">
<use id="SQUARE_MIX_PARAM" xlink:href="#knob-smallest" transform="translate(4 0)" />
- <text font-size="6pt" letter-spacing="2px" transform="translate(2 30)">MIX</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(2.5 30)">MIX</text>
<use id="SQUARE_MIX_INPUT" xlink:href="#input" transform="translate(0 35)" />
</g>
<g transform="translate(0 288)">
- <rect width="30" height="5" fill="#bbb" transform="translate(0 -5)" />
- <rect width="30" height="47" rx="5" fill="#bbb" transform="translate(0 -5)" />
+ <rect width="32" height="5" fill="#bbb" transform="translate(-1 -5)" />
+ <rect width="32" height="47" rx="5" fill="#bbb" transform="translate(-1 -5)" />
<g transform="translate(3 0)">
<use id="SQUARE_OUTPUT" xlink:href="#output" transform="translate(0 0)" />
<text font-size="6pt" letter-spacing="2px" transform="translate(2 36)">OUT</text>
@@ -351,10 +341,10 @@
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 90)" /> -->
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 177)" /> -->
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 267)" /> -->
- <text font-size="6pt" letter-spacing="2px" transform="translate(5 15)">SAW</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(4.3 15)">SAW</text>
<g transform="translate(3 30)">
<use id="SAW_SATURATION_PARAM" xlink:href="#knob-smallest" transform="translate(4 0)" />
- <text font-size="6pt" letter-spacing="2px" transform="translate(2 30)">SAT</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(2.5 30)">SAT</text>
<use id="SAW_SATURATION_INPUT" xlink:href="#input" transform="translate(0 35)" />
</g>
<g transform="translate(3 118)">
@@ -364,12 +354,12 @@
</g>
<g transform="translate(3 207)">
<use id="SAW_MIX_PARAM" xlink:href="#knob-smallest" transform="translate(4 0)" />
- <text font-size="6pt" letter-spacing="2px" transform="translate(2 30)">MIX</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(2.5 30)">MIX</text>
<use id="SAW_MIX_INPUT" xlink:href="#input" transform="translate(0 35)" />
</g>
<g transform="translate(0 288)">
- <rect width="30" height="5" fill="#bbb" transform="translate(0 -5)" />
- <rect width="30" height="47" rx="5" fill="#bbb" transform="translate(0 -5)" />
+ <rect width="32" height="5" fill="#bbb" transform="translate(-1 -5)" />
+ <rect width="32" height="47" rx="5" fill="#bbb" transform="translate(-1 -5)" />
<g transform="translate(3 0)">
<use id="SAW_OUTPUT" xlink:href="#output" transform="translate(0 0)" />
<text font-size="6pt" letter-spacing="2px" transform="translate(2 36)">OUT</text>
@@ -386,7 +376,7 @@
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 90)" /> -->
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 177)" /> -->
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 267)" /> -->
- <text font-size="6pt" letter-spacing="2px" transform="translate(5 15)">TRI</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(7 15)">TRI</text>
<g transform="translate(3 118)">
<use id="TRIANGLE_PHASE_PARAM" xlink:href="#knob-smallest" transform="translate(4 0)" />
<text font-size="6pt" letter-spacing="2px" transform="translate(2 30)">PHS</text>
@@ -394,12 +384,12 @@
</g>
<g transform="translate(3 207)">
<use id="TRIANGLE_MIX_PARAM" xlink:href="#knob-smallest" transform="translate(4 0)" />
- <text font-size="6pt" letter-spacing="2px" transform="translate(2 30)">MIX</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(2.5 30)">MIX</text>
<use id="TRIANGLE_MIX_INPUT" xlink:href="#input" transform="translate(0 35)" />
</g>
<g transform="translate(0 288)">
- <rect width="30" height="5" fill="#bbb" transform="translate(0 -5)" />
- <rect width="30" height="47" rx="5" fill="#bbb" transform="translate(0 -5)" />
+ <rect width="32" height="5" fill="#bbb" transform="translate(-1 -5)" />
+ <rect width="32" height="47" rx="5" fill="#bbb" transform="translate(-1 -5)" />
<g transform="translate(3 0)">
<use id="TRIANGLE_OUTPUT" xlink:href="#output" transform="translate(0 0)" />
<text font-size="6pt" letter-spacing="2px" transform="translate(2 36)">OUT</text>
@@ -415,7 +405,7 @@
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 90)" /> -->
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 177)" /> -->
<!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 267)" /> -->
- <text font-size="6pt" letter-spacing="2px" transform="translate(5 15)">SIN</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(6.5 15)">SIN</text>
<g transform="translate(3 118)">
<use id="SINE_PHASE_PARAM" xlink:href="#knob-smallest" transform="translate(4 0)" />
<text font-size="6pt" letter-spacing="2px" transform="translate(2 30)">PHS</text>
@@ -423,12 +413,12 @@
</g>
<g transform="translate(3 207)">
<use id="SINE_MIX_PARAM" xlink:href="#knob-smallest" transform="translate(4 0)" />
- <text font-size="6pt" letter-spacing="2px" transform="translate(2 30)">MIX</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(2.5 30)">MIX</text>
<use id="SINE_MIX_INPUT" xlink:href="#input" transform="translate(0 35)" />
</g>
<g transform="translate(0 288)">
- <rect width="30" height="5" fill="#bbb" transform="translate(0 -5)" />
- <rect width="30" height="47" rx="5" fill="#bbb" transform="translate(0 -5)" />
+ <rect width="31" height="5" fill="#bbb" transform="translate(-1 -5)" />
+ <rect width="31" height="47" rx="5" fill="#bbb" transform="translate(-1 -5)" />
<g transform="translate(3 0)">
<use id="SINE_OUTPUT" xlink:href="#output" transform="translate(0 0)" />
<text font-size="6pt" letter-spacing="2px" transform="translate(2 36)">OUT</text>
@@ -443,13 +433,13 @@
<rect width="70" height="47" rx="5" fill="#fafafa" transform="translate(10 0)" />
<g transform="translate(10 0)">
<rect width="30" height="47" rx="5" fill="#fafafa" />
- <use id="PITCH_INPUT" xlink:href="#input" transform="translate(3 5)" />
- <text font-size="6pt" letter-spacing="1px" transform="translate(1 40)">V/OCT</text>
+ <use id="PITCH_INPUT" xlink:href="#input" transform="translate(4 5)" />
+ <text font-size="6pt" letter-spacing="1px" transform="translate(2 40)">V/OCT</text>
</g>
<g transform="translate(50 0)">
<rect width="30" height="47" rx="5" fill="#fafafa" />
- <use id="SYNC_INPUT" xlink:href="#input" transform="translate(3 5)" />
- <text font-size="6pt" letter-spacing="2px" transform="translate(1 40)">SYNC</text>
+ <use id="SYNC_INPUT" xlink:href="#input" transform="translate(2 5)" />
+ <text font-size="6pt" letter-spacing="2px" transform="translate(0 40)">SYNC</text>
</g>
<g transform="translate(100 0)">
<rect width="30" height="47" rx="5" fill="#bbb" transform="translate(0 0)" />
diff --git a/res/VCO.svg b/res/VCO.svg
Binary files differ.
diff --git a/res/XCO.svg b/res/XCO.svg
Binary files differ.
diff --git a/src/VCO.cpp b/src/VCO.cpp
@@ -118,8 +118,8 @@ struct VCOWidget : ModuleWidget {
auto sineOutputPosition = Vec(113.0, 318.0);
auto slowLightPosition = Vec(90.0, 156.5);
- auto fmExpLightPosition = Vec(62.0, 235.0);
- auto fmLinLightPosition = Vec(62.0, 246.3);
+ auto fmExpLightPosition = Vec(62.0, 234.0);
+ auto fmLinLightPosition = Vec(62.0, 247.3);
// end generated by svg_widgets.rb
addParam(ParamWidget::create<Knob68>(frequencyParamPosition, module, VCO::FREQUENCY_PARAM, -3.0, 6.0, 0.0));
diff --git a/src/XCO.cpp b/src/XCO.cpp
@@ -1,13 +1,123 @@
#include "XCO.hpp"
+#include "dsp/pitch.hpp"
void XCO::onReset() {
+ _syncTrigger.reset();
+ _modulationStep = modulationSteps;
+}
+
+void XCO::onSampleRateChange() {
+ _phasor.setSampleRate(engineGetSampleRate());
+ _modulationStep = modulationSteps;
}
void XCO::step() {
- lights[SLOW_LIGHT].value = 1.0f;
- lights[FM_EXP_LIGHT].value = 1.0f;
- lights[FM_LIN_LIGHT].value = 1.0f;
+ lights[SLOW_LIGHT].value = _slowMode;
+ lights[FM_EXP_LIGHT].value = !_fmLinearMode;
+ lights[FM_LIN_LIGHT].value = _fmLinearMode;
+
+ if (!(
+ outputs[MIX_OUTPUT].active ||
+ outputs[SQUARE_OUTPUT].active ||
+ outputs[SAW_OUTPUT].active ||
+ outputs[TRIANGLE_OUTPUT].active ||
+ outputs[SINE_OUTPUT].active
+ )) {
+ return;
+ }
+
+ ++_modulationStep;
+ if (_modulationStep >= modulationSteps) {
+ _modulationStep = 0;
+
+ _baseVOct = params[FREQUENCY_PARAM].value;
+ _baseVOct += params[FINE_PARAM].value;
+ if (inputs[PITCH_INPUT].active) {
+ _baseVOct += clamp(inputs[PITCH_INPUT].value, -5.0f, 5.0f);
+ }
+ if ((_slowMode = ((int)params[SLOW_PARAM].value)) == 1) {
+ _baseVOct -= 5.0f;
+ }
+ _baseHz = cvToFrequency(_baseVOct);
+
+ if (_syncTrigger.process(inputs[SYNC_INPUT].value)) {
+ _phasor.setPhase(0.0f);
+ }
+
+ float pw = params[SQUARE_PW_PARAM].value;
+ if (inputs[SQUARE_PW_INPUT].active) {
+ pw *= clamp(inputs[SQUARE_PW_INPUT].value / 5.0f, -1.0f, 1.0f);
+ }
+ pw = (pw + 1.0f) / 2.0f;
+ pw *= 1.0f - 2.0f * _square.minPulseWidth;
+ _square.setPulseWidth(pw);
+
+ float saturation = params[SAW_SATURATION_PARAM].value;
+ if (inputs[SAW_SATURATION_INPUT].active) {
+ saturation *= clamp(inputs[SAW_SATURATION_INPUT].value / 10.0f, 0.0f, 1.0f);
+ }
+ _saw.setSaturation(saturation * 10.f);
+
+ _fmDepth = params[FM_PARAM].value;
+ _fmLinearMode = ((int)params[FM_TYPE_PARAM].value) == 1;
+
+ _squarePhaseOffset = phaseOffset(params[SQUARE_PHASE_PARAM], inputs[SQUARE_PHASE_INPUT]);
+ _sawPhaseOffset = phaseOffset(params[SAW_PHASE_PARAM], inputs[SAW_PHASE_INPUT]);
+ _trianglePhaseOffset = phaseOffset(params[TRIANGLE_PHASE_PARAM], inputs[TRIANGLE_PHASE_INPUT]);
+ _sinePhaseOffset = phaseOffset(params[SINE_PHASE_PARAM], inputs[SINE_PHASE_INPUT]);
+
+ _squareMix = level(params[SQUARE_MIX_PARAM], inputs[SQUARE_MIX_INPUT]);
+ _sawMix = level(params[SAW_MIX_PARAM], inputs[SAW_MIX_INPUT]);
+ _triangleMix = level(params[TRIANGLE_MIX_PARAM], inputs[TRIANGLE_MIX_INPUT]);
+ _sineMix = level(params[SINE_MIX_PARAM], inputs[SINE_MIX_INPUT]);
+ }
+
+ if (inputs[FM_INPUT].active) {
+ float fm = inputs[FM_INPUT].value * _fmDepth;
+ if (_fmLinearMode) {
+ _phasor.setFrequency(_baseHz + fm * _baseHz);
+ }
+ else {
+ _phasor.setFrequency(cvToFrequency(_baseVOct + fm));
+ }
+ }
+ else {
+ _phasor.setFrequency(_baseHz);
+ }
+ _phasor.advancePhase();
+ float mix = 0.0f;
+ if (outputs[MIX_OUTPUT].active || outputs[SQUARE_OUTPUT].active) {
+ mix += outputs[SQUARE_OUTPUT].value = amplitude * _squareMix * _square.nextFromPhasor(_phasor, _squarePhaseOffset);
+ }
+ if (outputs[MIX_OUTPUT].active || outputs[SAW_OUTPUT].active) {
+ mix += outputs[SAW_OUTPUT].value = amplitude * _sawMix * _saw.nextFromPhasor(_phasor, _sawPhaseOffset);
+ }
+ if (outputs[MIX_OUTPUT].active || outputs[TRIANGLE_OUTPUT].active) {
+ mix += outputs[TRIANGLE_OUTPUT].value = amplitude * _triangleMix * _triangle.nextFromPhasor(_phasor, _trianglePhaseOffset);
+ }
+ if (outputs[MIX_OUTPUT].active || outputs[SINE_OUTPUT].active) {
+ mix += outputs[SINE_OUTPUT].value = amplitude * _sineMix * _sine.nextFromPhasor(_phasor, _sinePhaseOffset);
+ }
+ if (outputs[MIX_OUTPUT].active) {
+ outputs[MIX_OUTPUT].value = mix;
+ }
+}
+
+float XCO::phaseOffset(Param& param, Input& input) {
+ float v = param.value;
+ if (input.active) {
+ v *= clamp(input.value / 5.0f, -1.0f, 1.0f);
+ }
+ return v;
+}
+
+float XCO::level(Param& param, Input& input) {
+ float v = param.value;
+ if (input.active) {
+ v *= clamp(input.value / 10.0f, 0.0f, 1.0f);
+ }
+ return v;
}
struct XCOWidget : ModuleWidget {
@@ -27,12 +137,12 @@ struct XCOWidget : ModuleWidget {
addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 365)));
// generated by svg_widgets.rb
- auto frequencyParamPosition = Vec(40.0, 50.0);
- auto fineParamPosition = Vec(65.5, 160.0);
- auto slowParamPosition = Vec(93.5, 193.5);
+ auto frequencyParamPosition = Vec(40.0, 45.0);
+ auto fineParamPosition = Vec(65.5, 156.0);
+ auto slowParamPosition = Vec(90.0, 191.7);
auto fmParamPosition = Vec(61.5, 219.5);
- auto fmTypeParamPosition = Vec(109.0, 275.0);
- auto squarePwmParamPosition = Vec(147.0, 60.0);
+ auto fmTypeParamPosition = Vec(103.0, 275.0);
+ auto squarePwParamPosition = Vec(147.0, 60.0);
auto squarePhaseParamPosition = Vec(147.0, 148.0);
auto squareMixParamPosition = Vec(147.0, 237.0);
auto sawSaturationParamPosition = Vec(187.0, 60.0);
@@ -44,7 +154,7 @@ struct XCOWidget : ModuleWidget {
auto sineMixParamPosition = Vec(267.0, 237.0);
auto fmInputPosition = Vec(34.0, 261.0);
- auto squarePwmInputPosition = Vec(143.0, 95.0);
+ auto squarePwInputPosition = Vec(143.0, 95.0);
auto squarePhaseInputPosition = Vec(143.0, 183.0);
auto squareMixInputPosition = Vec(143.0, 272.0);
auto sawSaturationInputPosition = Vec(183.0, 95.0);
@@ -54,8 +164,8 @@ struct XCOWidget : ModuleWidget {
auto triangleMixInputPosition = Vec(223.0, 272.0);
auto sinePhaseInputPosition = Vec(263.0, 183.0);
auto sineMixInputPosition = Vec(263.0, 272.0);
- auto pitchInputPosition = Vec(13.0, 318.0);
- auto syncInputPosition = Vec(53.0, 318.0);
+ auto pitchInputPosition = Vec(14.0, 318.0);
+ auto syncInputPosition = Vec(52.0, 318.0);
auto squareOutputPosition = Vec(143.0, 318.0);
auto sawOutputPosition = Vec(183.0, 318.0);
@@ -63,9 +173,9 @@ struct XCOWidget : ModuleWidget {
auto sineOutputPosition = Vec(263.0, 318.0);
auto mixOutputPosition = Vec(103.0, 318.0);
- auto slowLightPosition = Vec(45.5, 195.0);
- auto fmExpLightPosition = Vec(71.0, 267.5);
- auto fmLinLightPosition = Vec(71.0, 284.5);
+ auto slowLightPosition = Vec(50.0, 193.0);
+ auto fmExpLightPosition = Vec(73.0, 270.5);
+ auto fmLinLightPosition = Vec(73.0, 281.8);
// end generated by svg_widgets.rb
addParam(ParamWidget::create<Knob68>(frequencyParamPosition, module, XCO::FREQUENCY_PARAM, -3.0, 6.0, 0.0));
@@ -73,7 +183,7 @@ struct XCOWidget : ModuleWidget {
addParam(ParamWidget::create<StatefulButton9>(slowParamPosition, module, XCO::SLOW_PARAM, 0.0, 1.0, 0.0));
addParam(ParamWidget::create<Knob26>(fmParamPosition, module, XCO::FM_PARAM, 0.0, 1.0, 0.0));
addParam(ParamWidget::create<StatefulButton9>(fmTypeParamPosition, module, XCO::FM_TYPE_PARAM, 0.0, 1.0, 0.0));
- addParam(ParamWidget::create<Knob16>(squarePwmParamPosition, module, XCO::SQUARE_PWM_PARAM, -0.97, 0.97, 0.0));
+ addParam(ParamWidget::create<Knob16>(squarePwParamPosition, module, XCO::SQUARE_PW_PARAM, -0.97, 0.97, 0.0));
addParam(ParamWidget::create<Knob16>(squarePhaseParamPosition, module, XCO::SQUARE_PHASE_PARAM, -1.0, 1.0, 0.0));
addParam(ParamWidget::create<Knob16>(squareMixParamPosition, module, XCO::SQUARE_MIX_PARAM, 0.0, 1.0, 1.0));
addParam(ParamWidget::create<Knob16>(sawSaturationParamPosition, module, XCO::SAW_SATURATION_PARAM, 0.0, 1.0, 0.0));
@@ -85,7 +195,7 @@ struct XCOWidget : ModuleWidget {
addParam(ParamWidget::create<Knob16>(sineMixParamPosition, module, XCO::SINE_MIX_PARAM, 0.0, 1.0, 1.0));
addInput(Port::create<Port24>(fmInputPosition, Port::INPUT, module, XCO::FM_INPUT));
- addInput(Port::create<Port24>(squarePwmInputPosition, Port::INPUT, module, XCO::SQUARE_PWM_INPUT));
+ addInput(Port::create<Port24>(squarePwInputPosition, Port::INPUT, module, XCO::SQUARE_PW_INPUT));
addInput(Port::create<Port24>(squarePhaseInputPosition, Port::INPUT, module, XCO::SQUARE_PHASE_INPUT));
addInput(Port::create<Port24>(squareMixInputPosition, Port::INPUT, module, XCO::SQUARE_MIX_INPUT));
addInput(Port::create<Port24>(sawSaturationInputPosition, Port::INPUT, module, XCO::SAW_SATURATION_INPUT));
@@ -110,4 +220,4 @@ struct XCOWidget : ModuleWidget {
}
};
-Model* modelXCO = Model::create<XCO, XCOWidget>("Bogaudio", "Bogaudio-XCO", "XCO");
+Model* modelXCO = Model::create<XCO, XCOWidget>("Bogaudio", "Bogaudio-XCO", "XCO", OSCILLATOR_TAG);
diff --git a/src/XCO.hpp b/src/XCO.hpp
@@ -1,6 +1,9 @@
#pragma once
#include "bogaudio.hpp"
+#include "dsp/oscillator.hpp"
+
+using namespace bogaudio::dsp;
extern Model* modelXCO;
@@ -13,7 +16,7 @@ struct XCO : Module {
SLOW_PARAM,
FM_PARAM,
FM_TYPE_PARAM,
- SQUARE_PWM_PARAM,
+ SQUARE_PW_PARAM,
SQUARE_PHASE_PARAM,
SQUARE_MIX_PARAM,
SAW_SATURATION_PARAM,
@@ -28,7 +31,7 @@ struct XCO : Module {
enum InputsIds {
FM_INPUT,
- SQUARE_PWM_INPUT,
+ SQUARE_PW_INPUT,
SQUARE_PHASE_INPUT,
SQUARE_MIX_INPUT,
SAW_SATURATION_INPUT,
@@ -59,12 +62,48 @@ struct XCO : Module {
NUM_LIGHTS
};
- XCO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
+ const int modulationSteps = 100;
+ const float amplitude = 5.0f;
+ int _modulationStep = 0;
+ float _baseVOct = 0.0f;
+ float _baseHz = 0.0f;
+ bool _slowMode = false;
+ float _fmDepth = 0.0f;
+ bool _fmLinearMode = false;
+ float _squarePhaseOffset = 0.0f;
+ float _sawPhaseOffset = 0.0f;
+ float _trianglePhaseOffset = 0.0f;
+ float _sinePhaseOffset = 0.0f;
+ float _squareMix = 1.0f;
+ float _sawMix = 1.0f;
+ float _triangleMix = 1.0f;
+ float _sineMix = 1.0f;
+ SchmittTrigger _syncTrigger;
+
+ Phasor _phasor;
+ BandLimitedSquareOscillator _square;
+ BandLimitedSawOscillator _saw;
+ TriangleOscillator _triangle;
+ SineTableOscillator _sine;
+
+ XCO()
+ : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS)
+ , _phasor(engineGetSampleRate(), 1.0f)
+ , _square(0.0f, 0.0f)
+ , _saw(0.0f, 0.0f)
+ , _triangle(0.0f, 0.0f)
+ , _sine(0.0f, 0.0f)
+ {
onReset();
+ _saw.setQuality(12);
+ _square.setQuality(12);
}
virtual void onReset() override;
+ virtual void onSampleRateChange() override;
virtual void step() override;
+ float phaseOffset(Param& param, Input& input);
+ float level(Param& param, Input& input);
};
} // namespace bogaudio