@@ -4,6 +4,7 @@ | |||
"author": "VCV", | |||
"license": "BSD-3-Clause", | |||
"authorEmail": "contact@vcvrack.com", | |||
"pluginUrl": "https://vcvrack.com/Befaco.html", | |||
"authorUrl": "https://vcvrack.com/", | |||
"sourceUrl": "https://github.com/VCVRack/Befaco", | |||
"version": "1.0.0", | |||
@@ -1,5 +1,11 @@ | |||
#include "Befaco.hpp" | |||
#include "dsp/functions.hpp" | |||
static float clip(float x) { | |||
x = clamp(x, -2.f, 2.f); | |||
return x / std::pow(1.f + std::pow(x, 24.f), 1/24.f); | |||
} | |||
struct ABC : Module { | |||
@@ -32,66 +38,65 @@ struct ABC : Module { | |||
NUM_LIGHTS | |||
}; | |||
ABC() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||
void step() override; | |||
}; | |||
static float clip(float x) { | |||
x = clamp(x, -2.0f, 2.0f); | |||
return x / powf(1.0 + powf(x, 24.0), 1/24.0); | |||
} | |||
void ABC::step() { | |||
float a1 = inputs[A1_INPUT].value; | |||
float b1 = inputs[B1_INPUT].normalize(5.0) * 2.0*exponentialBipolar(80.0, params[B1_LEVEL_PARAM].value); | |||
float c1 = inputs[C1_INPUT].normalize(10.0) * exponentialBipolar(80.0, params[C1_LEVEL_PARAM].value); | |||
float out1 = a1 * b1 / 5.0 + c1; | |||
float a2 = inputs[A2_INPUT].value; | |||
float b2 = inputs[B2_INPUT].normalize(5.0) * 2.0*exponentialBipolar(80.0, params[B2_LEVEL_PARAM].value); | |||
float c2 = inputs[C2_INPUT].normalize(10.0) * exponentialBipolar(80.0, params[C2_LEVEL_PARAM].value); | |||
float out2 = a2 * b2 / 5.0 + c2; | |||
// Set outputs | |||
if (outputs[OUT1_OUTPUT].active) { | |||
outputs[OUT1_OUTPUT].value = clip(out1 / 10.0) * 10.0; | |||
} | |||
else { | |||
out2 += out1; | |||
} | |||
if (outputs[OUT2_OUTPUT].active) { | |||
outputs[OUT2_OUTPUT].value = clip(out2 / 10.0) * 10.0; | |||
ABC() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
params[B1_LEVEL_PARAM].config(-1.0, 1.0, 0.0, "B1 Level"); | |||
params[C1_LEVEL_PARAM].config(-1.0, 1.0, 0.0, "C1 Level"); | |||
params[B2_LEVEL_PARAM].config(-1.0, 1.0, 0.0, "B2 Level"); | |||
params[C2_LEVEL_PARAM].config(-1.0, 1.0, 0.0, "C2 Level"); | |||
} | |||
// Lights | |||
lights[OUT1_POS_LIGHT].value = fmaxf(0.0, out1 / 5.0); | |||
lights[OUT1_NEG_LIGHT].value = fmaxf(0.0, -out1 / 5.0); | |||
lights[OUT2_POS_LIGHT].value = fmaxf(0.0, out2 / 5.0); | |||
lights[OUT2_NEG_LIGHT].value = fmaxf(0.0, -out2 / 5.0); | |||
} | |||
void step() override { | |||
float a1 = inputs[A1_INPUT].value; | |||
float b1 = inputs[B1_INPUT].normalize(5.f) * 2.f*dsp::exponentialBipolar(80.f, params[B1_LEVEL_PARAM].value); | |||
float c1 = inputs[C1_INPUT].normalize(10.f) * dsp::exponentialBipolar(80.f, params[C1_LEVEL_PARAM].value); | |||
float out1 = a1 * b1 / 5.f + c1; | |||
float a2 = inputs[A2_INPUT].value; | |||
float b2 = inputs[B2_INPUT].normalize(5.f) * 2.f*dsp::exponentialBipolar(80.f, params[B2_LEVEL_PARAM].value); | |||
float c2 = inputs[C2_INPUT].normalize(10.f) * dsp::exponentialBipolar(80.f, params[C2_LEVEL_PARAM].value); | |||
float out2 = a2 * b2 / 5.f + c2; | |||
// Set outputs | |||
if (outputs[OUT1_OUTPUT].active) { | |||
outputs[OUT1_OUTPUT].value = clip(out1 / 10.f) * 10.f; | |||
} | |||
else { | |||
out2 += out1; | |||
} | |||
if (outputs[OUT2_OUTPUT].active) { | |||
outputs[OUT2_OUTPUT].value = clip(out2 / 10.f) * 10.f; | |||
} | |||
// Lights | |||
lights[OUT1_POS_LIGHT].setBrightnessSmooth(std::max(0.f, out1 / 5.f)); | |||
lights[OUT1_NEG_LIGHT].setBrightnessSmooth(std::max(0.f, -out1 / 5.f)); | |||
lights[OUT2_POS_LIGHT].setBrightnessSmooth(std::max(0.f, out2 / 5.f)); | |||
lights[OUT2_NEG_LIGHT].setBrightnessSmooth(std::max(0.f, -out2 / 5.f)); | |||
} | |||
}; | |||
struct ABCWidget : ModuleWidget { | |||
ABCWidget(ABC *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(assetPlugin(plugin, "res/ABC.svg"))); | |||
setPanel(SVG::load(asset::plugin(plugin, "res/ABC.svg"))); | |||
addChild(createWidget<Knurlie>(Vec(15, 0))); | |||
addChild(createWidget<Knurlie>(Vec(15, 365))); | |||
addParam(createParam<Davies1900hRedKnob>(Vec(45, 37), module, ABC::B1_LEVEL_PARAM, -1.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(45, 107), module, ABC::C1_LEVEL_PARAM, -1.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hRedKnob>(Vec(45, 204), module, ABC::B2_LEVEL_PARAM, -1.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(45, 274), module, ABC::C2_LEVEL_PARAM, -1.0, 1.0, 0.0)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 28), PortWidget::INPUT, module, ABC::A1_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 70), PortWidget::INPUT, module, ABC::B1_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 112), PortWidget::INPUT, module, ABC::C1_INPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(7, 154), PortWidget::OUTPUT, module, ABC::OUT1_OUTPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 195), PortWidget::INPUT, module, ABC::A2_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 237), PortWidget::INPUT, module, ABC::B2_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 279), PortWidget::INPUT, module, ABC::C2_INPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(7, 321), PortWidget::OUTPUT, module, ABC::OUT2_OUTPUT)); | |||
addParam(createParam<Davies1900hRedKnob>(Vec(45, 37), module, ABC::B1_LEVEL_PARAM)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(45, 107), module, ABC::C1_LEVEL_PARAM)); | |||
addParam(createParam<Davies1900hRedKnob>(Vec(45, 204), module, ABC::B2_LEVEL_PARAM)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(45, 274), module, ABC::C2_LEVEL_PARAM)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 28), module, ABC::A1_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 70), module, ABC::B1_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 112), module, ABC::C1_INPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(7, 154), module, ABC::OUT1_OUTPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 195), module, ABC::A2_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 237), module, ABC::B2_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 279), module, ABC::C2_INPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(7, 321), module, ABC::OUT2_OUTPUT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(37, 162), module, ABC::OUT1_POS_LIGHT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(37, 329), module, ABC::OUT2_POS_LIGHT)); | |||
@@ -5,8 +5,6 @@ Plugin *plugin; | |||
void init(rack::Plugin *p) { | |||
plugin = p; | |||
p->slug = TOSTRING(SLUG); | |||
p->version = TOSTRING(VERSION); | |||
p->addModel(modelEvenVCO); | |||
p->addModel(modelRampage); | |||
@@ -1,4 +1,5 @@ | |||
#include "rack0.hpp" | |||
#include "rack.hpp" | |||
#include "componentlibrary.hpp" | |||
using namespace rack; | |||
@@ -17,7 +18,7 @@ extern Model *modelDualAtenuverter; | |||
struct Knurlie : SVGScrew { | |||
Knurlie() { | |||
sw->svg = SVG::load(assetPlugin(plugin, "res/Knurlie.svg")); | |||
sw->svg = SVG::load(asset::plugin(plugin, "res/Knurlie.svg")); | |||
sw->wrap(); | |||
box.size = sw->box.size; | |||
} | |||
@@ -27,43 +27,47 @@ struct DualAtenuverter : Module { | |||
NUM_LIGHTS | |||
}; | |||
DualAtenuverter() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||
void step() override; | |||
}; | |||
DualAtenuverter() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
params[ATEN1_PARAM].config(-1.0, 1.0, 0.0); | |||
params[OFFSET1_PARAM].config(-10.0, 10.0, 0.0); | |||
params[ATEN2_PARAM].config(-1.0, 1.0, 0.0); | |||
params[OFFSET2_PARAM].config(-10.0, 10.0, 0.0); | |||
} | |||
void DualAtenuverter::step() { | |||
float out1 = inputs[IN1_INPUT].value * params[ATEN1_PARAM].value + params[OFFSET1_PARAM].value; | |||
float out2 = inputs[IN2_INPUT].value * params[ATEN2_PARAM].value + params[OFFSET2_PARAM].value; | |||
out1 = clamp(out1, -10.0f, 10.0f); | |||
out2 = clamp(out2, -10.0f, 10.0f); | |||
void step() override { | |||
float out1 = inputs[IN1_INPUT].value * params[ATEN1_PARAM].value + params[OFFSET1_PARAM].value; | |||
float out2 = inputs[IN2_INPUT].value * params[ATEN2_PARAM].value + params[OFFSET2_PARAM].value; | |||
out1 = clamp(out1, -10.f, 10.f); | |||
out2 = clamp(out2, -10.f, 10.f); | |||
outputs[OUT1_OUTPUT].value = out1; | |||
outputs[OUT2_OUTPUT].value = out2; | |||
lights[OUT1_POS_LIGHT].value = fmaxf(0.0, out1 / 5.0); | |||
lights[OUT1_NEG_LIGHT].value = fmaxf(0.0, -out1 / 5.0); | |||
lights[OUT2_POS_LIGHT].value = fmaxf(0.0, out2 / 5.0); | |||
lights[OUT2_NEG_LIGHT].value = fmaxf(0.0, -out2 / 5.0); | |||
} | |||
outputs[OUT1_OUTPUT].value = out1; | |||
outputs[OUT2_OUTPUT].value = out2; | |||
lights[OUT1_POS_LIGHT].setBrightnessSmooth(std::max(0.f, out1 / 5.f)); | |||
lights[OUT1_NEG_LIGHT].setBrightnessSmooth(std::max(0.f, -out1 / 5.f)); | |||
lights[OUT2_POS_LIGHT].setBrightnessSmooth(std::max(0.f, out2 / 5.f)); | |||
lights[OUT2_NEG_LIGHT].setBrightnessSmooth(std::max(0.f, -out2 / 5.f)); | |||
} | |||
}; | |||
struct DualAtenuverterWidget : ModuleWidget { | |||
DualAtenuverterWidget(DualAtenuverter *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(assetPlugin(plugin, "res/DualAtenuverter.svg"))); | |||
setPanel(SVG::load(asset::plugin(plugin, "res/DualAtenuverter.svg"))); | |||
addChild(createWidget<Knurlie>(Vec(15, 0))); | |||
addChild(createWidget<Knurlie>(Vec(15, 365))); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(20, 33), module, DualAtenuverter::ATEN1_PARAM, -1.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hRedKnob>(Vec(20, 91), module, DualAtenuverter::OFFSET1_PARAM, -10.0, 10.0, 0.0)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(20, 201), module, DualAtenuverter::ATEN2_PARAM, -1.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hRedKnob>(Vec(20, 260), module, DualAtenuverter::OFFSET2_PARAM, -10.0, 10.0, 0.0)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(20, 33), module, DualAtenuverter::ATEN1_PARAM)); | |||
addParam(createParam<Davies1900hRedKnob>(Vec(20, 91), module, DualAtenuverter::OFFSET1_PARAM)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(20, 201), module, DualAtenuverter::ATEN2_PARAM)); | |||
addParam(createParam<Davies1900hRedKnob>(Vec(20, 260), module, DualAtenuverter::OFFSET2_PARAM)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 152), PortWidget::INPUT, module, DualAtenuverter::IN1_INPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(43, 152), PortWidget::OUTPUT, module, DualAtenuverter::OUT1_OUTPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 152), module, DualAtenuverter::IN1_INPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(43, 152), module, DualAtenuverter::OUT1_OUTPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 319), PortWidget::INPUT, module, DualAtenuverter::IN2_INPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(43, 319), PortWidget::OUTPUT, module, DualAtenuverter::OUT2_OUTPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 319), module, DualAtenuverter::IN2_INPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(43, 319), module, DualAtenuverter::OUT2_OUTPUT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(33, 143), module, DualAtenuverter::OUT1_POS_LIGHT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(33, 311), module, DualAtenuverter::OUT2_POS_LIGHT)); | |||
@@ -1,6 +1,4 @@ | |||
#include "Befaco.hpp" | |||
#include "dsp/minblep.hpp" | |||
#include "dsp/filter.hpp" | |||
struct EvenVCO : Module { | |||
@@ -35,127 +33,128 @@ struct EvenVCO : Module { | |||
/** Whether we are past the pulse width already */ | |||
bool halfPhase = false; | |||
MinBLEP<16> triSquareMinBLEP; | |||
MinBLEP<16> triMinBLEP; | |||
MinBLEP<16> sineMinBLEP; | |||
MinBLEP<16> doubleSawMinBLEP; | |||
MinBLEP<16> sawMinBLEP; | |||
MinBLEP<16> squareMinBLEP; | |||
RCFilter triFilter; | |||
EvenVCO(); | |||
void step() override; | |||
}; | |||
EvenVCO::EvenVCO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | |||
triSquareMinBLEP.minblep = minblep_16_32; | |||
triSquareMinBLEP.oversample = 32; | |||
triMinBLEP.minblep = minblep_16_32; | |||
triMinBLEP.oversample = 32; | |||
sineMinBLEP.minblep = minblep_16_32; | |||
sineMinBLEP.oversample = 32; | |||
doubleSawMinBLEP.minblep = minblep_16_32; | |||
doubleSawMinBLEP.oversample = 32; | |||
sawMinBLEP.minblep = minblep_16_32; | |||
sawMinBLEP.oversample = 32; | |||
squareMinBLEP.minblep = minblep_16_32; | |||
squareMinBLEP.oversample = 32; | |||
} | |||
void EvenVCO::step() { | |||
// Compute frequency, pitch is 1V/oct | |||
float pitch = 1.0 + roundf(params[OCTAVE_PARAM].value) + params[TUNE_PARAM].value / 12.0; | |||
pitch += inputs[PITCH1_INPUT].value + inputs[PITCH2_INPUT].value; | |||
pitch += inputs[FM_INPUT].value / 4.0; | |||
float freq = 261.626 * powf(2.0, pitch); | |||
freq = clamp(freq, 0.0f, 20000.0f); | |||
// Pulse width | |||
float pw = params[PWM_PARAM].value + inputs[PWM_INPUT].value / 5.0; | |||
const float minPw = 0.05; | |||
pw = rescale(clamp(pw, -1.0f, 1.0f), -1.0f, 1.0f, minPw, 1.0f - minPw); | |||
// Advance phase | |||
float deltaPhase = clamp(freq * engineGetSampleTime(), 1e-6f, 0.5f); | |||
float oldPhase = phase; | |||
phase += deltaPhase; | |||
if (oldPhase < 0.5 && phase >= 0.5) { | |||
float crossing = -(phase - 0.5) / deltaPhase; | |||
triSquareMinBLEP.jump(crossing, 2.0); | |||
doubleSawMinBLEP.jump(crossing, -2.0); | |||
} | |||
if (!halfPhase && phase >= pw) { | |||
float crossing = -(phase - pw) / deltaPhase; | |||
squareMinBLEP.jump(crossing, 2.0); | |||
halfPhase = true; | |||
dsp::MinBLEP<16> triSquareMinBLEP; | |||
dsp::MinBLEP<16> triMinBLEP; | |||
dsp::MinBLEP<16> sineMinBLEP; | |||
dsp::MinBLEP<16> doubleSawMinBLEP; | |||
dsp::MinBLEP<16> sawMinBLEP; | |||
dsp::MinBLEP<16> squareMinBLEP; | |||
dsp::RCFilter triFilter; | |||
EvenVCO() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | |||
params[OCTAVE_PARAM].config(-5.0, 4.0, 0.0, "Octave", " Hz", 2, dsp::FREQ_C4); | |||
params[TUNE_PARAM].config(-7.0, 7.0, 0.0, "Tune"); | |||
params[PWM_PARAM].config(-1.0, 1.0, 0.0, "Pulse width"); | |||
triSquareMinBLEP.minblep = dsp::minblep_16_32; | |||
triSquareMinBLEP.oversample = 32; | |||
triMinBLEP.minblep = dsp::minblep_16_32; | |||
triMinBLEP.oversample = 32; | |||
sineMinBLEP.minblep = dsp::minblep_16_32; | |||
sineMinBLEP.oversample = 32; | |||
doubleSawMinBLEP.minblep = dsp::minblep_16_32; | |||
doubleSawMinBLEP.oversample = 32; | |||
sawMinBLEP.minblep = dsp::minblep_16_32; | |||
sawMinBLEP.oversample = 32; | |||
squareMinBLEP.minblep = dsp::minblep_16_32; | |||
squareMinBLEP.oversample = 32; | |||
} | |||
// Reset phase if at end of cycle | |||
if (phase >= 1.0) { | |||
phase -= 1.0; | |||
float crossing = -phase / deltaPhase; | |||
triSquareMinBLEP.jump(crossing, -2.0); | |||
doubleSawMinBLEP.jump(crossing, -2.0); | |||
squareMinBLEP.jump(crossing, -2.0); | |||
sawMinBLEP.jump(crossing, -2.0); | |||
halfPhase = false; | |||
void step() override { | |||
// Compute frequency, pitch is 1V/oct | |||
float pitch = 1.f + std::round(params[OCTAVE_PARAM].value) + params[TUNE_PARAM].value / 12.f; | |||
pitch += inputs[PITCH1_INPUT].value + inputs[PITCH2_INPUT].value; | |||
pitch += inputs[FM_INPUT].value / 4.f; | |||
float freq = dsp::FREQ_C4 * std::pow(2.f, pitch); | |||
freq = clamp(freq, 0.f, 20000.f); | |||
// Pulse width | |||
float pw = params[PWM_PARAM].value + inputs[PWM_INPUT].value / 5.f; | |||
const float minPw = 0.05; | |||
pw = rescale(clamp(pw, -1.f, 1.f), -1.f, 1.f, minPw, 1.f - minPw); | |||
// Advance phase | |||
float deltaPhase = clamp(freq * app()->engine->getSampleTime(), 1e-6f, 0.5f); | |||
float oldPhase = phase; | |||
phase += deltaPhase; | |||
if (oldPhase < 0.5 && phase >= 0.5) { | |||
float crossing = -(phase - 0.5) / deltaPhase; | |||
triSquareMinBLEP.jump(crossing, 2.f); | |||
doubleSawMinBLEP.jump(crossing, -2.f); | |||
} | |||
if (!halfPhase && phase >= pw) { | |||
float crossing = -(phase - pw) / deltaPhase; | |||
squareMinBLEP.jump(crossing, 2.f); | |||
halfPhase = true; | |||
} | |||
// Reset phase if at end of cycle | |||
if (phase >= 1.f) { | |||
phase -= 1.f; | |||
float crossing = -phase / deltaPhase; | |||
triSquareMinBLEP.jump(crossing, -2.f); | |||
doubleSawMinBLEP.jump(crossing, -2.f); | |||
squareMinBLEP.jump(crossing, -2.f); | |||
sawMinBLEP.jump(crossing, -2.f); | |||
halfPhase = false; | |||
} | |||
// Outputs | |||
float triSquare = (phase < 0.5) ? -1.f : 1.f; | |||
triSquare += triSquareMinBLEP.shift(); | |||
// Integrate square for triangle | |||
tri += 4.f * triSquare * freq * app()->engine->getSampleTime(); | |||
tri *= (1.f - 40.f * app()->engine->getSampleTime()); | |||
float sine = -std::cos(2*M_PI * phase); | |||
float doubleSaw = (phase < 0.5) ? (-1.f + 4.f*phase) : (-1.f + 4.f*(phase - 0.5)); | |||
doubleSaw += doubleSawMinBLEP.shift(); | |||
float even = 0.55 * (doubleSaw + 1.27 * sine); | |||
float saw = -1.f + 2.f*phase; | |||
saw += sawMinBLEP.shift(); | |||
float square = (phase < pw) ? -1.f : 1.f; | |||
square += squareMinBLEP.shift(); | |||
// Set outputs | |||
outputs[TRI_OUTPUT].value = 5.f*tri; | |||
outputs[SINE_OUTPUT].value = 5.f*sine; | |||
outputs[EVEN_OUTPUT].value = 5.f*even; | |||
outputs[SAW_OUTPUT].value = 5.f*saw; | |||
outputs[SQUARE_OUTPUT].value = 5.f*square; | |||
} | |||
// Outputs | |||
float triSquare = (phase < 0.5) ? -1.0 : 1.0; | |||
triSquare += triSquareMinBLEP.shift(); | |||
// Integrate square for triangle | |||
tri += 4.0 * triSquare * freq * engineGetSampleTime(); | |||
tri *= (1.0 - 40.0 * engineGetSampleTime()); | |||
float sine = -cosf(2*M_PI * phase); | |||
float doubleSaw = (phase < 0.5) ? (-1.0 + 4.0*phase) : (-1.0 + 4.0*(phase - 0.5)); | |||
doubleSaw += doubleSawMinBLEP.shift(); | |||
float even = 0.55 * (doubleSaw + 1.27 * sine); | |||
float saw = -1.0 + 2.0*phase; | |||
saw += sawMinBLEP.shift(); | |||
float square = (phase < pw) ? -1.0 : 1.0; | |||
square += squareMinBLEP.shift(); | |||
// Set outputs | |||
outputs[TRI_OUTPUT].value = 5.0*tri; | |||
outputs[SINE_OUTPUT].value = 5.0*sine; | |||
outputs[EVEN_OUTPUT].value = 5.0*even; | |||
outputs[SAW_OUTPUT].value = 5.0*saw; | |||
outputs[SQUARE_OUTPUT].value = 5.0*square; | |||
} | |||
}; | |||
struct EvenVCOWidget : ModuleWidget { | |||
EvenVCOWidget(EvenVCO *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(assetPlugin(plugin, "res/EvenVCO.svg"))); | |||
setPanel(SVG::load(asset::plugin(plugin, "res/EvenVCO.svg"))); | |||
addChild(createWidget<Knurlie>(Vec(15, 0))); | |||
addChild(createWidget<Knurlie>(Vec(15, 365))); | |||
addChild(createWidget<Knurlie>(Vec(15*6, 0))); | |||
addChild(createWidget<Knurlie>(Vec(15*6, 365))); | |||
addParam(createParam<BefacoBigSnapKnob>(Vec(22, 32), module, EvenVCO::OCTAVE_PARAM, -5.0, 4.0, 0.0)); | |||
addParam(createParam<BefacoTinyKnob>(Vec(73, 131), module, EvenVCO::TUNE_PARAM, -7.0, 7.0, 0.0)); | |||
addParam(createParam<Davies1900hRedKnob>(Vec(16, 230), module, EvenVCO::PWM_PARAM, -1.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoBigSnapKnob>(Vec(22, 32), module, EvenVCO::OCTAVE_PARAM)); | |||
addParam(createParam<BefacoTinyKnob>(Vec(73, 131), module, EvenVCO::TUNE_PARAM)); | |||
addParam(createParam<Davies1900hRedKnob>(Vec(16, 230), module, EvenVCO::PWM_PARAM)); | |||
addInput(createPort<PJ301MPort>(Vec(8, 120), PortWidget::INPUT, module, EvenVCO::PITCH1_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(19, 157), PortWidget::INPUT, module, EvenVCO::PITCH2_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(48, 183), PortWidget::INPUT, module, EvenVCO::FM_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(86, 189), PortWidget::INPUT, module, EvenVCO::SYNC_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(8, 120), module, EvenVCO::PITCH1_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(19, 157), module, EvenVCO::PITCH2_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(48, 183), module, EvenVCO::FM_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(86, 189), module, EvenVCO::SYNC_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(72, 236), PortWidget::INPUT, module, EvenVCO::PWM_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(72, 236), module, EvenVCO::PWM_INPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(10, 283), PortWidget::OUTPUT, module, EvenVCO::TRI_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(87, 283), PortWidget::OUTPUT, module, EvenVCO::SINE_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(48, 306), PortWidget::OUTPUT, module, EvenVCO::EVEN_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(10, 327), PortWidget::OUTPUT, module, EvenVCO::SAW_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(87, 327), PortWidget::OUTPUT, module, EvenVCO::SQUARE_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(10, 283), module, EvenVCO::TRI_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(87, 283), module, EvenVCO::SINE_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(48, 306), module, EvenVCO::EVEN_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(10, 327), module, EvenVCO::SAW_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(87, 327), module, EvenVCO::SQUARE_OUTPUT)); | |||
} | |||
}; | |||
@@ -27,45 +27,51 @@ struct Mixer : Module { | |||
NUM_LIGHTS | |||
}; | |||
Mixer() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||
void step() override; | |||
}; | |||
Mixer() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
params[CH1_PARAM].config(0.0, 1.0, 0.0); | |||
params[CH2_PARAM].config(0.0, 1.0, 0.0); | |||
params[CH3_PARAM].config(0.0, 1.0, 0.0); | |||
params[CH4_PARAM].config(0.0, 1.0, 0.0); | |||
} | |||
void step() override { | |||
float in1 = inputs[IN1_INPUT].value * params[CH1_PARAM].value; | |||
float in2 = inputs[IN2_INPUT].value * params[CH2_PARAM].value; | |||
float in3 = inputs[IN3_INPUT].value * params[CH3_PARAM].value; | |||
float in4 = inputs[IN4_INPUT].value * params[CH4_PARAM].value; | |||
float out = in1 + in2 + in3 + in4; | |||
outputs[OUT1_OUTPUT].value = out; | |||
outputs[OUT2_OUTPUT].value = -out; | |||
lights[OUT_POS_LIGHT].setBrightnessSmooth(out / 5.f); | |||
lights[OUT_NEG_LIGHT].setBrightnessSmooth(-out / 5.f); | |||
} | |||
}; | |||
void Mixer::step() { | |||
float in1 = inputs[IN1_INPUT].value * params[CH1_PARAM].value; | |||
float in2 = inputs[IN2_INPUT].value * params[CH2_PARAM].value; | |||
float in3 = inputs[IN3_INPUT].value * params[CH3_PARAM].value; | |||
float in4 = inputs[IN4_INPUT].value * params[CH4_PARAM].value; | |||
float out = in1 + in2 + in3 + in4; | |||
outputs[OUT1_OUTPUT].value = out; | |||
outputs[OUT2_OUTPUT].value = -out; | |||
lights[OUT_POS_LIGHT].setBrightnessSmooth(out / 5.0); | |||
lights[OUT_NEG_LIGHT].setBrightnessSmooth(-out / 5.0); | |||
} | |||
struct MixerWidget : ModuleWidget { | |||
MixerWidget(Mixer *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Mixer.svg"))); | |||
setPanel(SVG::load(asset::plugin(plugin, "res/Mixer.svg"))); | |||
addChild(createWidget<Knurlie>(Vec(15, 0))); | |||
addChild(createWidget<Knurlie>(Vec(15, 365))); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(19, 32), module, Mixer::CH1_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(19, 85), module, Mixer::CH2_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(19, 137), module, Mixer::CH3_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(19, 190), module, Mixer::CH4_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(19, 32), module, Mixer::CH1_PARAM)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(19, 85), module, Mixer::CH2_PARAM)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(19, 137), module, Mixer::CH3_PARAM)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(19, 190), module, Mixer::CH4_PARAM)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 242), PortWidget::INPUT, module, Mixer::IN1_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(43, 242), PortWidget::INPUT, module, Mixer::IN2_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 242), module, Mixer::IN1_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(43, 242), module, Mixer::IN2_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 281), PortWidget::INPUT, module, Mixer::IN3_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(43, 281), PortWidget::INPUT, module, Mixer::IN4_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 281), module, Mixer::IN3_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(43, 281), module, Mixer::IN4_INPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(7, 324), PortWidget::OUTPUT, module, Mixer::OUT1_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(43, 324), PortWidget::OUTPUT, module, Mixer::OUT2_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(7, 324), module, Mixer::OUT1_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(43, 324), module, Mixer::OUT2_OUTPUT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(32.7, 310), module, Mixer::OUT_POS_LIGHT)); | |||
} | |||
@@ -1,5 +1,17 @@ | |||
#include "Befaco.hpp" | |||
#include "dsp/digital.hpp" | |||
static float shapeDelta(float delta, float tau, float shape) { | |||
float lin = sgn(delta) * 10.f / tau; | |||
if (shape < 0.f) { | |||
float log = sgn(delta) * 40.f / tau / (std::abs(delta) + 1.f); | |||
return crossfade(lin, log, -shape * 0.95f); | |||
} | |||
else { | |||
float exp = M_E * delta / tau; | |||
return crossfade(lin, exp, shape * 0.90f); | |||
} | |||
} | |||
struct Rampage : Module { | |||
@@ -63,158 +75,161 @@ struct Rampage : Module { | |||
float out[2] = {}; | |||
bool gate[2] = {}; | |||
SchmittTrigger trigger[2]; | |||
PulseGenerator endOfCyclePulse[2]; | |||
Rampage() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||
void step() override; | |||
}; | |||
static float shapeDelta(float delta, float tau, float shape) { | |||
float lin = sgn(delta) * 10.0 / tau; | |||
if (shape < 0.0) { | |||
float log = sgn(delta) * 40.0 / tau / (fabsf(delta) + 1.0); | |||
return crossfade(lin, log, -shape * 0.95f); | |||
} | |||
else { | |||
float exp = M_E * delta / tau; | |||
return crossfade(lin, exp, shape * 0.90f); | |||
dsp::SchmittTrigger trigger[2]; | |||
dsp::PulseGenerator endOfCyclePulse[2]; | |||
Rampage() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
params[RANGE_A_PARAM].config(0.0, 2.0, 0.0); | |||
params[SHAPE_A_PARAM].config(-1.0, 1.0, 0.0); | |||
params[TRIGG_A_PARAM].config(0.0, 1.0, 0.0); | |||
params[RISE_A_PARAM].config(0.0, 1.0, 0.0); | |||
params[FALL_A_PARAM].config(0.0, 1.0, 0.0); | |||
params[CYCLE_A_PARAM].config(0.0, 1.0, 0.0); | |||
params[RANGE_B_PARAM].config(0.0, 2.0, 0.0); | |||
params[SHAPE_B_PARAM].config(-1.0, 1.0, 0.0); | |||
params[TRIGG_B_PARAM].config(0.0, 1.0, 0.0); | |||
params[RISE_B_PARAM].config(0.0, 1.0, 0.0); | |||
params[FALL_B_PARAM].config(0.0, 1.0, 0.0); | |||
params[CYCLE_B_PARAM].config(0.0, 1.0, 0.0); | |||
params[BALANCE_PARAM].config(0.0, 1.0, 0.5); | |||
} | |||
} | |||
void Rampage::step() { | |||
for (int c = 0; c < 2; c++) { | |||
float in = inputs[IN_A_INPUT + c].value; | |||
if (trigger[c].process(params[TRIGG_A_PARAM + c].value * 10.0 + inputs[TRIGG_A_INPUT + c].value / 2.0)) { | |||
gate[c] = true; | |||
} | |||
if (gate[c]) { | |||
in = 10.0; | |||
} | |||
void step() override { | |||
for (int c = 0; c < 2; c++) { | |||
float in = inputs[IN_A_INPUT + c].value; | |||
if (trigger[c].process(params[TRIGG_A_PARAM + c].value * 10.0 + inputs[TRIGG_A_INPUT + c].value / 2.0)) { | |||
gate[c] = true; | |||
} | |||
if (gate[c]) { | |||
in = 10.0; | |||
} | |||
float shape = params[SHAPE_A_PARAM + c].value; | |||
float delta = in - out[c]; | |||
float shape = params[SHAPE_A_PARAM + c].value; | |||
float delta = in - out[c]; | |||
// Integrator | |||
float minTime; | |||
switch ((int) params[RANGE_A_PARAM + c].value) { | |||
case 0: minTime = 1e-2; break; | |||
case 1: minTime = 1e-3; break; | |||
default: minTime = 1e-1; break; | |||
} | |||
// Integrator | |||
float minTime; | |||
switch ((int) params[RANGE_A_PARAM + c].value) { | |||
case 0: minTime = 1e-2; break; | |||
case 1: minTime = 1e-3; break; | |||
default: minTime = 1e-1; break; | |||
} | |||
bool rising = false; | |||
bool falling = false; | |||
if (delta > 0) { | |||
// Rise | |||
float riseCv = params[RISE_A_PARAM + c].value - inputs[EXP_CV_A_INPUT + c].value / 10.0 + inputs[RISE_CV_A_INPUT + c].value / 10.0; | |||
riseCv = clamp(riseCv, 0.0f, 1.0f); | |||
float rise = minTime * powf(2.0, riseCv * 10.0); | |||
out[c] += shapeDelta(delta, rise, shape) * engineGetSampleTime(); | |||
rising = (in - out[c] > 1e-3); | |||
if (!rising) { | |||
gate[c] = false; | |||
bool rising = false; | |||
bool falling = false; | |||
if (delta > 0) { | |||
// Rise | |||
float riseCv = params[RISE_A_PARAM + c].value - inputs[EXP_CV_A_INPUT + c].value / 10.0 + inputs[RISE_CV_A_INPUT + c].value / 10.0; | |||
riseCv = clamp(riseCv, 0.0f, 1.0f); | |||
float rise = minTime * std::pow(2.0, riseCv * 10.0); | |||
out[c] += shapeDelta(delta, rise, shape) * app()->engine->getSampleTime(); | |||
rising = (in - out[c] > 1e-3); | |||
if (!rising) { | |||
gate[c] = false; | |||
} | |||
} | |||
} | |||
else if (delta < 0) { | |||
// Fall | |||
float fallCv = params[FALL_A_PARAM + c].value - inputs[EXP_CV_A_INPUT + c].value / 10.0 + inputs[FALL_CV_A_INPUT + c].value / 10.0; | |||
fallCv = clamp(fallCv, 0.0f, 1.0f); | |||
float fall = minTime * powf(2.0, fallCv * 10.0); | |||
out[c] += shapeDelta(delta, fall, shape) * engineGetSampleTime(); | |||
falling = (in - out[c] < -1e-3); | |||
if (!falling) { | |||
// End of cycle, check if we should turn the gate back on (cycle mode) | |||
endOfCyclePulse[c].trigger(1e-3); | |||
if (params[CYCLE_A_PARAM + c].value * 10.0 + inputs[CYCLE_A_INPUT + c].value >= 4.0) { | |||
gate[c] = true; | |||
else if (delta < 0) { | |||
// Fall | |||
float fallCv = params[FALL_A_PARAM + c].value - inputs[EXP_CV_A_INPUT + c].value / 10.0 + inputs[FALL_CV_A_INPUT + c].value / 10.0; | |||
fallCv = clamp(fallCv, 0.0f, 1.0f); | |||
float fall = minTime * std::pow(2.0, fallCv * 10.0); | |||
out[c] += shapeDelta(delta, fall, shape) * app()->engine->getSampleTime(); | |||
falling = (in - out[c] < -1e-3); | |||
if (!falling) { | |||
// End of cycle, check if we should turn the gate back on (cycle mode) | |||
endOfCyclePulse[c].trigger(1e-3); | |||
if (params[CYCLE_A_PARAM + c].value * 10.0 + inputs[CYCLE_A_INPUT + c].value >= 4.0) { | |||
gate[c] = true; | |||
} | |||
} | |||
} | |||
} | |||
else { | |||
gate[c] = false; | |||
} | |||
else { | |||
gate[c] = false; | |||
} | |||
if (!rising && !falling) { | |||
out[c] = in; | |||
if (!rising && !falling) { | |||
out[c] = in; | |||
} | |||
outputs[RISING_A_OUTPUT + c].value = (rising ? 10.0 : 0.0); | |||
outputs[FALLING_A_OUTPUT + c].value = (falling ? 10.0 : 0.0); | |||
lights[RISING_A_LIGHT + c].setBrightnessSmooth(rising ? 1.0 : 0.0); | |||
lights[FALLING_A_LIGHT + c].setBrightnessSmooth(falling ? 1.0 : 0.0); | |||
outputs[EOC_A_OUTPUT + c].value = (endOfCyclePulse[c].process(app()->engine->getSampleTime()) ? 10.0 : 0.0); | |||
outputs[OUT_A_OUTPUT + c].value = out[c]; | |||
lights[OUT_A_LIGHT + c].setBrightnessSmooth(out[c] / 10.0); | |||
} | |||
outputs[RISING_A_OUTPUT + c].value = (rising ? 10.0 : 0.0); | |||
outputs[FALLING_A_OUTPUT + c].value = (falling ? 10.0 : 0.0); | |||
lights[RISING_A_LIGHT + c].setBrightnessSmooth(rising ? 1.0 : 0.0); | |||
lights[FALLING_A_LIGHT + c].setBrightnessSmooth(falling ? 1.0 : 0.0); | |||
outputs[EOC_A_OUTPUT + c].value = (endOfCyclePulse[c].process(engineGetSampleTime()) ? 10.0 : 0.0); | |||
outputs[OUT_A_OUTPUT + c].value = out[c]; | |||
lights[OUT_A_LIGHT + c].setBrightnessSmooth(out[c] / 10.0); | |||
// Logic | |||
float balance = params[BALANCE_PARAM].value; | |||
float a = out[0]; | |||
float b = out[1]; | |||
if (balance < 0.5) | |||
b *= 2.0 * balance; | |||
else if (balance > 0.5) | |||
a *= 2.0 * (1.0 - balance); | |||
outputs[COMPARATOR_OUTPUT].value = (b > a ? 10.0 : 0.0); | |||
outputs[MIN_OUTPUT].value = std::min(a, b); | |||
outputs[MAX_OUTPUT].value = std::max(a, b); | |||
// Lights | |||
lights[COMPARATOR_LIGHT].setBrightnessSmooth(outputs[COMPARATOR_OUTPUT].value / 10.0); | |||
lights[MIN_LIGHT].setBrightnessSmooth(outputs[MIN_OUTPUT].value / 10.0); | |||
lights[MAX_LIGHT].setBrightnessSmooth(outputs[MAX_OUTPUT].value / 10.0); | |||
} | |||
}; | |||
// Logic | |||
float balance = params[BALANCE_PARAM].value; | |||
float a = out[0]; | |||
float b = out[1]; | |||
if (balance < 0.5) | |||
b *= 2.0 * balance; | |||
else if (balance > 0.5) | |||
a *= 2.0 * (1.0 - balance); | |||
outputs[COMPARATOR_OUTPUT].value = (b > a ? 10.0 : 0.0); | |||
outputs[MIN_OUTPUT].value = fminf(a, b); | |||
outputs[MAX_OUTPUT].value = fmaxf(a, b); | |||
// Lights | |||
lights[COMPARATOR_LIGHT].setBrightnessSmooth(outputs[COMPARATOR_OUTPUT].value / 10.0); | |||
lights[MIN_LIGHT].setBrightnessSmooth(outputs[MIN_OUTPUT].value / 10.0); | |||
lights[MAX_LIGHT].setBrightnessSmooth(outputs[MAX_OUTPUT].value / 10.0); | |||
} | |||
struct RampageWidget : ModuleWidget { | |||
RampageWidget(Rampage *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Rampage.svg"))); | |||
setPanel(SVG::load(asset::plugin(plugin, "res/Rampage.svg"))); | |||
addChild(createWidget<Knurlie>(Vec(15, 0))); | |||
addChild(createWidget<Knurlie>(Vec(box.size.x-30, 0))); | |||
addChild(createWidget<Knurlie>(Vec(15, 365))); | |||
addChild(createWidget<Knurlie>(Vec(box.size.x-30, 365))); | |||
addInput(createPort<PJ301MPort>(Vec(14, 30), PortWidget::INPUT, module, Rampage::IN_A_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(52, 37), PortWidget::INPUT, module, Rampage::TRIGG_A_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(8, 268), PortWidget::INPUT, module, Rampage::RISE_CV_A_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(67, 268), PortWidget::INPUT, module, Rampage::FALL_CV_A_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(38, 297), PortWidget::INPUT, module, Rampage::EXP_CV_A_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(102, 290), PortWidget::INPUT, module, Rampage::CYCLE_A_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(229, 30), PortWidget::INPUT, module, Rampage::IN_B_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(192, 37), PortWidget::INPUT, module, Rampage::TRIGG_B_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(176, 268), PortWidget::INPUT, module, Rampage::RISE_CV_B_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(237, 268), PortWidget::INPUT, module, Rampage::FALL_CV_B_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(207, 297), PortWidget::INPUT, module, Rampage::EXP_CV_B_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(143, 290), PortWidget::INPUT, module, Rampage::CYCLE_B_INPUT)); | |||
addParam(createParam<BefacoSwitch>(Vec(94, 32), module, Rampage::RANGE_A_PARAM, 0.0, 2.0, 0.0)); | |||
addParam(createParam<BefacoTinyKnob>(Vec(27, 90), module, Rampage::SHAPE_A_PARAM, -1.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoPush>(Vec(72, 82), module, Rampage::TRIGG_A_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSlidePot>(Vec(16, 135), module, Rampage::RISE_A_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSlidePot>(Vec(57, 135), module, Rampage::FALL_A_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSwitch>(Vec(101, 238), module, Rampage::CYCLE_A_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSwitch>(Vec(147, 32), module, Rampage::RANGE_B_PARAM, 0.0, 2.0, 0.0)); | |||
addParam(createParam<BefacoTinyKnob>(Vec(217, 90), module, Rampage::SHAPE_B_PARAM, -1.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoPush>(Vec(170, 82), module, Rampage::TRIGG_B_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSlidePot>(Vec(197, 135), module, Rampage::RISE_B_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSlidePot>(Vec(238, 135), module, Rampage::FALL_B_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSwitch>(Vec(141, 238), module, Rampage::CYCLE_B_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(117, 76), module, Rampage::BALANCE_PARAM, 0.0, 1.0, 0.5)); | |||
addOutput(createPort<PJ301MPort>(Vec(8, 326), PortWidget::OUTPUT, module, Rampage::RISING_A_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(68, 326), PortWidget::OUTPUT, module, Rampage::FALLING_A_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(104, 326), PortWidget::OUTPUT, module, Rampage::EOC_A_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(102, 195), PortWidget::OUTPUT, module, Rampage::OUT_A_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(177, 326), PortWidget::OUTPUT, module, Rampage::RISING_B_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(237, 326), PortWidget::OUTPUT, module, Rampage::FALLING_B_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(140, 326), PortWidget::OUTPUT, module, Rampage::EOC_B_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(142, 195), PortWidget::OUTPUT, module, Rampage::OUT_B_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(122, 133), PortWidget::OUTPUT, module, Rampage::COMPARATOR_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(89, 157), PortWidget::OUTPUT, module, Rampage::MIN_OUTPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(155, 157), PortWidget::OUTPUT, module, Rampage::MAX_OUTPUT)); | |||
addParam(createParam<BefacoSwitch>(Vec(94, 32), module, Rampage::RANGE_A_PARAM)); | |||
addParam(createParam<BefacoTinyKnob>(Vec(27, 90), module, Rampage::SHAPE_A_PARAM)); | |||
addParam(createParam<BefacoPush>(Vec(72, 82), module, Rampage::TRIGG_A_PARAM)); | |||
addParam(createParam<BefacoSlidePot>(Vec(16, 135), module, Rampage::RISE_A_PARAM)); | |||
addParam(createParam<BefacoSlidePot>(Vec(57, 135), module, Rampage::FALL_A_PARAM)); | |||
addParam(createParam<BefacoSwitch>(Vec(101, 238), module, Rampage::CYCLE_A_PARAM)); | |||
addParam(createParam<BefacoSwitch>(Vec(147, 32), module, Rampage::RANGE_B_PARAM)); | |||
addParam(createParam<BefacoTinyKnob>(Vec(217, 90), module, Rampage::SHAPE_B_PARAM)); | |||
addParam(createParam<BefacoPush>(Vec(170, 82), module, Rampage::TRIGG_B_PARAM)); | |||
addParam(createParam<BefacoSlidePot>(Vec(197, 135), module, Rampage::RISE_B_PARAM)); | |||
addParam(createParam<BefacoSlidePot>(Vec(238, 135), module, Rampage::FALL_B_PARAM)); | |||
addParam(createParam<BefacoSwitch>(Vec(141, 238), module, Rampage::CYCLE_B_PARAM)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(117, 76), module, Rampage::BALANCE_PARAM)); | |||
addInput(createInput<PJ301MPort>(Vec(14, 30), module, Rampage::IN_A_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(52, 37), module, Rampage::TRIGG_A_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(8, 268), module, Rampage::RISE_CV_A_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(67, 268), module, Rampage::FALL_CV_A_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(38, 297), module, Rampage::EXP_CV_A_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(102, 290), module, Rampage::CYCLE_A_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(229, 30), module, Rampage::IN_B_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(192, 37), module, Rampage::TRIGG_B_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(176, 268), module, Rampage::RISE_CV_B_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(237, 268), module, Rampage::FALL_CV_B_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(207, 297), module, Rampage::EXP_CV_B_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(143, 290), module, Rampage::CYCLE_B_INPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(8, 326), module, Rampage::RISING_A_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(68, 326), module, Rampage::FALLING_A_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(104, 326), module, Rampage::EOC_A_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(102, 195), module, Rampage::OUT_A_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(177, 326), module, Rampage::RISING_B_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(237, 326), module, Rampage::FALLING_B_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(140, 326), module, Rampage::EOC_B_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(142, 195), module, Rampage::OUT_B_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(122, 133), module, Rampage::COMPARATOR_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(89, 157), module, Rampage::MIN_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(155, 157), module, Rampage::MAX_OUTPUT)); | |||
addChild(createLight<SmallLight<RedLight>>(Vec(132, 167), module, Rampage::COMPARATOR_LIGHT)); | |||
addChild(createLight<SmallLight<RedLight>>(Vec(123, 174), module, Rampage::MIN_LIGHT)); | |||
@@ -21,61 +21,64 @@ struct SlewLimiter : Module { | |||
float out = 0.0; | |||
SlewLimiter() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} | |||
void step() override; | |||
}; | |||
void ::SlewLimiter::step() { | |||
float in = inputs[IN_INPUT].value; | |||
float shape = params[SHAPE_PARAM].value; | |||
// minimum and maximum slopes in volts per second | |||
const float slewMin = 0.1; | |||
const float slewMax = 10000.0; | |||
// Amount of extra slew per voltage difference | |||
const float shapeScale = 1/10.0; | |||
// Rise | |||
if (in > out) { | |||
float rise = inputs[RISE_INPUT].value / 10.0 + params[RISE_PARAM].value; | |||
float slew = slewMax * powf(slewMin / slewMax, rise); | |||
out += slew * crossfade(1.0f, shapeScale * (in - out), shape) * engineGetSampleTime(); | |||
if (out > in) | |||
out = in; | |||
} | |||
// Fall | |||
else if (in < out) { | |||
float fall = inputs[FALL_INPUT].value / 10.0 + params[FALL_PARAM].value; | |||
float slew = slewMax * powf(slewMin / slewMax, fall); | |||
out -= slew * crossfade(1.0f, shapeScale * (out - in), shape) * engineGetSampleTime(); | |||
if (out < in) | |||
out = in; | |||
SlewLimiter() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | |||
params[SHAPE_PARAM].config(0.0, 1.0, 0.0); | |||
params[RISE_PARAM].config(0.0, 1.0, 0.0); | |||
params[FALL_PARAM].config(0.0, 1.0, 0.0); | |||
} | |||
outputs[OUT_OUTPUT].value = out; | |||
} | |||
void step() override { | |||
float in = inputs[IN_INPUT].value; | |||
float shape = params[SHAPE_PARAM].value; | |||
// minimum and maximum slopes in volts per second | |||
const float slewMin = 0.1; | |||
const float slewMax = 10000.f; | |||
// Amount of extra slew per voltage difference | |||
const float shapeScale = 1/10.f; | |||
// Rise | |||
if (in > out) { | |||
float rise = inputs[RISE_INPUT].value / 10.f + params[RISE_PARAM].value; | |||
float slew = slewMax * powf(slewMin / slewMax, rise); | |||
out += slew * crossfade(1.f, shapeScale * (in - out), shape) * app()->engine->getSampleTime(); | |||
if (out > in) | |||
out = in; | |||
} | |||
// Fall | |||
else if (in < out) { | |||
float fall = inputs[FALL_INPUT].value / 10.f + params[FALL_PARAM].value; | |||
float slew = slewMax * powf(slewMin / slewMax, fall); | |||
out -= slew * crossfade(1.f, shapeScale * (out - in), shape) * app()->engine->getSampleTime(); | |||
if (out < in) | |||
out = in; | |||
} | |||
outputs[OUT_OUTPUT].value = out; | |||
} | |||
}; | |||
struct SlewLimiterWidget : ModuleWidget { | |||
SlewLimiterWidget(SlewLimiter *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(assetPlugin(plugin, "res/SlewLimiter.svg"))); | |||
SlewLimiterWidget(::SlewLimiter *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(asset::plugin(plugin, "res/SlewLimiter.svg"))); | |||
addChild(createWidget<Knurlie>(Vec(15, 0))); | |||
addChild(createWidget<Knurlie>(Vec(15, 365))); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(27, 39), module, ::SlewLimiter::SHAPE_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(27, 39), module, ::SlewLimiter::SHAPE_PARAM)); | |||
addParam(createParam<BefacoSlidePot>(Vec(15, 102), module, ::SlewLimiter::RISE_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSlidePot>(Vec(60, 102), module, ::SlewLimiter::FALL_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSlidePot>(Vec(15, 102), module, ::SlewLimiter::RISE_PARAM)); | |||
addParam(createParam<BefacoSlidePot>(Vec(60, 102), module, ::SlewLimiter::FALL_PARAM)); | |||
addInput(createPort<PJ301MPort>(Vec(10, 273), PortWidget::INPUT, module, ::SlewLimiter::RISE_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(55, 273), PortWidget::INPUT, module, ::SlewLimiter::FALL_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(10, 273), module, ::SlewLimiter::RISE_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(55, 273), module, ::SlewLimiter::FALL_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(10, 323), PortWidget::INPUT, module, ::SlewLimiter::IN_INPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(55, 323), PortWidget::OUTPUT, module, ::SlewLimiter::OUT_OUTPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(10, 323), module, ::SlewLimiter::IN_INPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(55, 323), module, ::SlewLimiter::OUT_OUTPUT)); | |||
} | |||
}; | |||
Model *modelSlewLimiter = createModel<SlewLimiter, SlewLimiterWidget>("SlewLimiter"); | |||
Model *modelSlewLimiter = createModel<::SlewLimiter, SlewLimiterWidget>("SlewLimiter"); |
@@ -1,10 +1,5 @@ | |||
#include <string.h> | |||
#include "Befaco.hpp" | |||
#include "dsp/functions.hpp" | |||
#include "dsp/samplerate.hpp" | |||
#include "dsp/ringbuffer.hpp" | |||
#include "dsp/filter.hpp" | |||
#include "dsp/fir.hpp" | |||
#include "pffft.h" | |||
@@ -13,6 +8,7 @@ BINARY(src_SpringReverbIR_pcm); | |||
static const size_t BLOCK_SIZE = 1024; | |||
struct SpringReverb : Module { | |||
enum ParamIds { | |||
WET_PARAM, | |||
@@ -40,131 +36,132 @@ struct SpringReverb : Module { | |||
NUM_LIGHTS = VU1_LIGHT + 7 | |||
}; | |||
RealTimeConvolver *convolver = NULL; | |||
SampleRateConverter<1> inputSrc; | |||
SampleRateConverter<1> outputSrc; | |||
DoubleRingBuffer<Frame<1>, 16*BLOCK_SIZE> inputBuffer; | |||
DoubleRingBuffer<Frame<1>, 16*BLOCK_SIZE> outputBuffer; | |||
dsp::RealTimeConvolver *convolver = NULL; | |||
dsp::SampleRateConverter<1> inputSrc; | |||
dsp::SampleRateConverter<1> outputSrc; | |||
dsp::DoubleRingBuffer<dsp::Frame<1>, 16*BLOCK_SIZE> inputBuffer; | |||
dsp::DoubleRingBuffer<dsp::Frame<1>, 16*BLOCK_SIZE> outputBuffer; | |||
RCFilter dryFilter; | |||
PeakFilter vuFilter; | |||
PeakFilter lightFilter; | |||
dsp::RCFilter dryFilter; | |||
dsp::PeakFilter vuFilter; | |||
dsp::PeakFilter lightFilter; | |||
SpringReverb(); | |||
~SpringReverb(); | |||
void step() override; | |||
}; | |||
SpringReverb() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
params[WET_PARAM].config(0.0, 1.0, 0.5); | |||
params[LEVEL1_PARAM].config(0.0, 1.0, 0.0); | |||
params[LEVEL2_PARAM].config(0.0, 1.0, 0.0); | |||
params[HPF_PARAM].config(0.0, 1.0, 0.5); | |||
convolver = new dsp::RealTimeConvolver(BLOCK_SIZE); | |||
SpringReverb::SpringReverb() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||
convolver = new RealTimeConvolver(BLOCK_SIZE); | |||
const float *kernel = (const float*) BINARY_START(src_SpringReverbIR_pcm); | |||
size_t kernelLen = BINARY_SIZE(src_SpringReverbIR_pcm) / sizeof(float); | |||
convolver->setKernel(kernel, kernelLen); | |||
} | |||
SpringReverb::~SpringReverb() { | |||
delete convolver; | |||
} | |||
void SpringReverb::step() { | |||
float in1 = inputs[IN1_INPUT].value; | |||
float in2 = inputs[IN2_INPUT].value; | |||
const float levelScale = 0.030; | |||
const float levelBase = 25.0; | |||
float level1 = levelScale * exponentialBipolar(levelBase, params[LEVEL1_PARAM].value) * inputs[CV1_INPUT].normalize(10.0) / 10.0; | |||
float level2 = levelScale * exponentialBipolar(levelBase, params[LEVEL2_PARAM].value) * inputs[CV2_INPUT].normalize(10.0) / 10.0; | |||
float dry = in1 * level1 + in2 * level2; | |||
// HPF on dry | |||
float dryCutoff = 200.0 * powf(20.0, params[HPF_PARAM].value) * engineGetSampleTime(); | |||
dryFilter.setCutoff(dryCutoff); | |||
dryFilter.process(dry); | |||
// Add dry to input buffer | |||
if (!inputBuffer.full()) { | |||
Frame<1> inputFrame; | |||
inputFrame.samples[0] = dryFilter.highpass(); | |||
inputBuffer.push(inputFrame); | |||
const float *kernel = (const float*) BINARY_START(src_SpringReverbIR_pcm); | |||
size_t kernelLen = BINARY_SIZE(src_SpringReverbIR_pcm) / sizeof(float); | |||
convolver->setKernel(kernel, kernelLen); | |||
} | |||
~SpringReverb() { | |||
delete convolver; | |||
} | |||
if (outputBuffer.empty()) { | |||
float input[BLOCK_SIZE] = {}; | |||
float output[BLOCK_SIZE]; | |||
// Convert input buffer | |||
{ | |||
inputSrc.setRates(engineGetSampleRate(), 48000); | |||
int inLen = inputBuffer.size(); | |||
int outLen = BLOCK_SIZE; | |||
inputSrc.process(inputBuffer.startData(), &inLen, (Frame<1>*) input, &outLen); | |||
inputBuffer.startIncr(inLen); | |||
void step() override { | |||
float in1 = inputs[IN1_INPUT].value; | |||
float in2 = inputs[IN2_INPUT].value; | |||
const float levelScale = 0.030; | |||
const float levelBase = 25.0; | |||
float level1 = levelScale * dsp::exponentialBipolar(levelBase, params[LEVEL1_PARAM].value) * inputs[CV1_INPUT].normalize(10.0) / 10.0; | |||
float level2 = levelScale * dsp::exponentialBipolar(levelBase, params[LEVEL2_PARAM].value) * inputs[CV2_INPUT].normalize(10.0) / 10.0; | |||
float dry = in1 * level1 + in2 * level2; | |||
// HPF on dry | |||
float dryCutoff = 200.0 * std::pow(20.0, params[HPF_PARAM].value) * app()->engine->getSampleTime(); | |||
dryFilter.setCutoff(dryCutoff); | |||
dryFilter.process(dry); | |||
// Add dry to input buffer | |||
if (!inputBuffer.full()) { | |||
dsp::Frame<1> inputFrame; | |||
inputFrame.samples[0] = dryFilter.highpass(); | |||
inputBuffer.push(inputFrame); | |||
} | |||
// Convolve block | |||
convolver->processBlock(input, output); | |||
// Convert output buffer | |||
{ | |||
outputSrc.setRates(48000, engineGetSampleRate()); | |||
int inLen = BLOCK_SIZE; | |||
int outLen = outputBuffer.capacity(); | |||
outputSrc.process((Frame<1>*) output, &inLen, outputBuffer.endData(), &outLen); | |||
outputBuffer.endIncr(outLen); | |||
if (outputBuffer.empty()) { | |||
float input[BLOCK_SIZE] = {}; | |||
float output[BLOCK_SIZE]; | |||
// Convert input buffer | |||
{ | |||
inputSrc.setRates(app()->engine->getSampleRate(), 48000); | |||
int inLen = inputBuffer.size(); | |||
int outLen = BLOCK_SIZE; | |||
inputSrc.process(inputBuffer.startData(), &inLen, (dsp::Frame<1>*) input, &outLen); | |||
inputBuffer.startIncr(inLen); | |||
} | |||
// Convolve block | |||
convolver->processBlock(input, output); | |||
// Convert output buffer | |||
{ | |||
outputSrc.setRates(48000, app()->engine->getSampleRate()); | |||
int inLen = BLOCK_SIZE; | |||
int outLen = outputBuffer.capacity(); | |||
outputSrc.process((dsp::Frame<1>*) output, &inLen, outputBuffer.endData(), &outLen); | |||
outputBuffer.endIncr(outLen); | |||
} | |||
} | |||
} | |||
// Set output | |||
if (outputBuffer.empty()) | |||
return; | |||
float wet = outputBuffer.shift().samples[0]; | |||
float balance = clamp(params[WET_PARAM].value + inputs[MIX_CV_INPUT].value / 10.0f, 0.0f, 1.0f); | |||
float mix = crossfade(in1, wet, balance); | |||
outputs[WET_OUTPUT].value = clamp(wet, -10.0f, 10.0f); | |||
outputs[MIX_OUTPUT].value = clamp(mix, -10.0f, 10.0f); | |||
// Set lights | |||
float lightRate = 5.0 * engineGetSampleTime(); | |||
vuFilter.setRate(lightRate); | |||
vuFilter.process(fabsf(wet)); | |||
lightFilter.setRate(lightRate); | |||
lightFilter.process(fabsf(dry*50.0)); | |||
float vuValue = vuFilter.peak(); | |||
for (int i = 0; i < 7; i++) { | |||
float light = powf(1.413, i) * vuValue / 10.0 - 1.0; | |||
lights[VU1_LIGHT + i].value = clamp(light, 0.0f, 1.0f); | |||
// Set output | |||
if (outputBuffer.empty()) | |||
return; | |||
float wet = outputBuffer.shift().samples[0]; | |||
float balance = clamp(params[WET_PARAM].value + inputs[MIX_CV_INPUT].value / 10.0f, 0.0f, 1.0f); | |||
float mix = crossfade(in1, wet, balance); | |||
outputs[WET_OUTPUT].value = clamp(wet, -10.0f, 10.0f); | |||
outputs[MIX_OUTPUT].value = clamp(mix, -10.0f, 10.0f); | |||
// Set lights | |||
float lightRate = 5.0 * app()->engine->getSampleTime(); | |||
vuFilter.setRate(lightRate); | |||
vuFilter.process(std::abs(wet)); | |||
lightFilter.setRate(lightRate); | |||
lightFilter.process(std::abs(dry*50.0)); | |||
float vuValue = vuFilter.peak(); | |||
for (int i = 0; i < 7; i++) { | |||
float light = std::pow(1.413, i) * vuValue / 10.0 - 1.0; | |||
lights[VU1_LIGHT + i].value = clamp(light, 0.0f, 1.0f); | |||
} | |||
lights[PEAK_LIGHT].value = lightFilter.peak(); | |||
} | |||
lights[PEAK_LIGHT].value = lightFilter.peak(); | |||
} | |||
}; | |||
struct SpringReverbWidget : ModuleWidget { | |||
SpringReverbWidget(SpringReverb *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(assetPlugin(plugin, "res/SpringReverb.svg"))); | |||
setPanel(SVG::load(asset::plugin(plugin, "res/SpringReverb.svg"))); | |||
addChild(createWidget<Knurlie>(Vec(15, 0))); | |||
addChild(createWidget<Knurlie>(Vec(15, 365))); | |||
addChild(createWidget<Knurlie>(Vec(15*6, 0))); | |||
addChild(createWidget<Knurlie>(Vec(15*6, 365))); | |||
addParam(createParam<BefacoBigKnob>(Vec(22, 29), module, SpringReverb::WET_PARAM, 0.0, 1.0, 0.5)); | |||
addParam(createParam<BefacoBigKnob>(Vec(22, 29), module, SpringReverb::WET_PARAM)); | |||
addParam(createParam<BefacoSlidePot>(Vec(12, 116), module, SpringReverb::LEVEL1_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSlidePot>(Vec(93, 116), module, SpringReverb::LEVEL2_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<BefacoSlidePot>(Vec(12, 116), module, SpringReverb::LEVEL1_PARAM)); | |||
addParam(createParam<BefacoSlidePot>(Vec(93, 116), module, SpringReverb::LEVEL2_PARAM)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(42, 210), module, SpringReverb::HPF_PARAM, 0.0, 1.0, 0.5)); | |||
addParam(createParam<Davies1900hWhiteKnob>(Vec(42, 210), module, SpringReverb::HPF_PARAM)); | |||
addInput(createPort<PJ301MPort>(Vec(7, 243), PortWidget::INPUT, module, SpringReverb::CV1_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(88, 243), PortWidget::INPUT, module, SpringReverb::CV2_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(27, 281), PortWidget::INPUT, module, SpringReverb::IN1_INPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(67, 281), PortWidget::INPUT, module, SpringReverb::IN2_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(7, 243), module, SpringReverb::CV1_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(88, 243), module, SpringReverb::CV2_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(27, 281), module, SpringReverb::IN1_INPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(67, 281), module, SpringReverb::IN2_INPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(7, 317), PortWidget::OUTPUT, module, SpringReverb::MIX_OUTPUT)); | |||
addInput(createPort<PJ301MPort>(Vec(47, 324), PortWidget::INPUT, module, SpringReverb::MIX_CV_INPUT)); | |||
addOutput(createPort<PJ301MPort>(Vec(88, 317), PortWidget::OUTPUT, module, SpringReverb::WET_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(7, 317), module, SpringReverb::MIX_OUTPUT)); | |||
addInput(createInput<PJ301MPort>(Vec(47, 324), module, SpringReverb::MIX_CV_INPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(88, 317), module, SpringReverb::WET_OUTPUT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(55, 269), module, SpringReverb::PEAK_LIGHT)); | |||
addChild(createLight<MediumLight<RedLight>>(Vec(55, 113), module, SpringReverb::VU1_LIGHT + 0)); | |||