@@ -3,32 +3,45 @@ | |||||
struct _8vert : Module { | struct _8vert : Module { | ||||
enum ParamIds { | enum ParamIds { | ||||
NUM_PARAMS = 8 | |||||
ENUMS(GAIN_PARAMS, 8), | |||||
NUM_PARAMS | |||||
}; | }; | ||||
enum InputIds { | enum InputIds { | ||||
NUM_INPUTS = 8 | |||||
ENUMS(IN_INPUTS, 8), | |||||
NUM_INPUTS | |||||
}; | }; | ||||
enum OutputIds { | enum OutputIds { | ||||
NUM_OUTPUTS = 8 | |||||
ENUMS(OUT_OUTPUTS, 8), | |||||
NUM_OUTPUTS | |||||
}; | }; | ||||
enum LightIds { | enum LightIds { | ||||
NUM_LIGHTS = 16 | |||||
ENUMS(OUT_LIGHTS, 8*2), | |||||
NUM_LIGHTS | |||||
}; | }; | ||||
_8vert() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||||
void step() override; | |||||
}; | |||||
_8vert() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
params[GAIN_PARAMS + 0].config(-1.f, 1.f, 0.f); | |||||
params[GAIN_PARAMS + 1].config(-1.f, 1.f, 0.f); | |||||
params[GAIN_PARAMS + 2].config(-1.f, 1.f, 0.f); | |||||
params[GAIN_PARAMS + 3].config(-1.f, 1.f, 0.f); | |||||
params[GAIN_PARAMS + 4].config(-1.f, 1.f, 0.f); | |||||
params[GAIN_PARAMS + 5].config(-1.f, 1.f, 0.f); | |||||
params[GAIN_PARAMS + 6].config(-1.f, 1.f, 0.f); | |||||
params[GAIN_PARAMS + 7].config(-1.f, 1.f, 0.f); | |||||
} | |||||
void _8vert::step() { | |||||
float lastIn = 10.0f; | |||||
for (int i = 0; i < 8; i++) { | |||||
lastIn = inputs[i].normalize(lastIn); | |||||
float out = lastIn * params[i].value; | |||||
outputs[i].value = out; | |||||
lights[2*i + 0].setBrightnessSmooth(fmaxf(0.0f, out / 5.0f)); | |||||
lights[2*i + 1].setBrightnessSmooth(fmaxf(0.0f, -out / 5.0f)); | |||||
void step() override { | |||||
float lastIn = 10.f; | |||||
for (int i = 0; i < 8; i++) { | |||||
lastIn = inputs[i].normalize(lastIn); | |||||
float out = lastIn * params[i].value; | |||||
outputs[i].value = out; | |||||
lights[2*i + 0].setBrightnessSmooth(std::max(0.f, out / 5.f)); | |||||
lights[2*i + 1].setBrightnessSmooth(std::max(0.f, -out / 5.f)); | |||||
} | |||||
} | } | ||||
} | |||||
}; | |||||
struct _8vertWidget : ModuleWidget { | struct _8vertWidget : ModuleWidget { | ||||
@@ -36,48 +49,48 @@ struct _8vertWidget : ModuleWidget { | |||||
}; | }; | ||||
_8vertWidget::_8vertWidget(_8vert *module) : ModuleWidget(module) { | _8vertWidget::_8vertWidget(_8vert *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/8vert.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/8vert.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | addChild(createWidget<ScrewSilver>(Vec(15, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | addChild(createWidget<ScrewSilver>(Vec(15, 365))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365))); | ||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 47.753), module, 0, -1.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 86.198), module, 1, -1.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 124.639), module, 2, -1.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 163.084), module, 3, -1.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 201.529), module, 4, -1.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 239.974), module, 5, -1.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 278.415), module, 6, -1.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 316.86), module, 7, -1.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 47.753), module, _8vert::GAIN_PARAMS + 0)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 86.198), module, _8vert::GAIN_PARAMS + 1)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 124.639), module, _8vert::GAIN_PARAMS + 2)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 163.084), module, _8vert::GAIN_PARAMS + 3)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 201.529), module, _8vert::GAIN_PARAMS + 4)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 239.974), module, _8vert::GAIN_PARAMS + 5)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 278.415), module, _8vert::GAIN_PARAMS + 6)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(45.308, 316.86), module, _8vert::GAIN_PARAMS + 7)); | |||||
addInput(createPort<PJ301MPort>(Vec(9.507, 50.397), PortWidget::INPUT, module, 0)); | |||||
addInput(createPort<PJ301MPort>(Vec(9.507, 88.842), PortWidget::INPUT, module, 1)); | |||||
addInput(createPort<PJ301MPort>(Vec(9.507, 127.283), PortWidget::INPUT, module, 2)); | |||||
addInput(createPort<PJ301MPort>(Vec(9.507, 165.728), PortWidget::INPUT, module, 3)); | |||||
addInput(createPort<PJ301MPort>(Vec(9.507, 204.173), PortWidget::INPUT, module, 4)); | |||||
addInput(createPort<PJ301MPort>(Vec(9.507, 242.614), PortWidget::INPUT, module, 5)); | |||||
addInput(createPort<PJ301MPort>(Vec(9.507, 281.059), PortWidget::INPUT, module, 6)); | |||||
addInput(createPort<PJ301MPort>(Vec(9.507, 319.504), PortWidget::INPUT, module, 7)); | |||||
addInput(createInput<PJ301MPort>(Vec(9.507, 50.397), module, _8vert::IN_INPUTS + 0)); | |||||
addInput(createInput<PJ301MPort>(Vec(9.507, 88.842), module, _8vert::IN_INPUTS + 1)); | |||||
addInput(createInput<PJ301MPort>(Vec(9.507, 127.283), module, _8vert::IN_INPUTS + 2)); | |||||
addInput(createInput<PJ301MPort>(Vec(9.507, 165.728), module, _8vert::IN_INPUTS + 3)); | |||||
addInput(createInput<PJ301MPort>(Vec(9.507, 204.173), module, _8vert::IN_INPUTS + 4)); | |||||
addInput(createInput<PJ301MPort>(Vec(9.507, 242.614), module, _8vert::IN_INPUTS + 5)); | |||||
addInput(createInput<PJ301MPort>(Vec(9.507, 281.059), module, _8vert::IN_INPUTS + 6)); | |||||
addInput(createInput<PJ301MPort>(Vec(9.507, 319.504), module, _8vert::IN_INPUTS + 7)); | |||||
addOutput(createPort<PJ301MPort>(Vec(86.393, 50.397), PortWidget::OUTPUT, module, 0)); | |||||
addOutput(createPort<PJ301MPort>(Vec(86.393, 88.842), PortWidget::OUTPUT, module, 1)); | |||||
addOutput(createPort<PJ301MPort>(Vec(86.393, 127.283), PortWidget::OUTPUT, module, 2)); | |||||
addOutput(createPort<PJ301MPort>(Vec(86.393, 165.728), PortWidget::OUTPUT, module, 3)); | |||||
addOutput(createPort<PJ301MPort>(Vec(86.393, 204.173), PortWidget::OUTPUT, module, 4)); | |||||
addOutput(createPort<PJ301MPort>(Vec(86.393, 242.614), PortWidget::OUTPUT, module, 5)); | |||||
addOutput(createPort<PJ301MPort>(Vec(86.393, 281.059), PortWidget::OUTPUT, module, 6)); | |||||
addOutput(createPort<PJ301MPort>(Vec(86.393, 319.504), PortWidget::OUTPUT, module, 7)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(86.393, 50.397), module, _8vert::OUT_OUTPUTS + 0)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(86.393, 88.842), module, _8vert::OUT_OUTPUTS + 1)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(86.393, 127.283), module, _8vert::OUT_OUTPUTS + 2)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(86.393, 165.728), module, _8vert::OUT_OUTPUTS + 3)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(86.393, 204.173), module, _8vert::OUT_OUTPUTS + 4)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(86.393, 242.614), module, _8vert::OUT_OUTPUTS + 5)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(86.393, 281.059), module, _8vert::OUT_OUTPUTS + 6)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(86.393, 319.504), module, _8vert::OUT_OUTPUTS + 7)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 50.414), module, 0)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 88.859), module, 2)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 127.304), module, 4)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 165.745), module, 6)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 204.19), module, 8)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 242.635), module, 10)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 281.076), module, 12)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 319.521), module, 14)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 50.414), module, _8vert::OUT_LIGHTS + 0*2)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 88.859), module, _8vert::OUT_LIGHTS + 1*2)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 127.304), module, _8vert::OUT_LIGHTS + 2*2)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 165.745), module, _8vert::OUT_LIGHTS + 3*2)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 204.19), module, _8vert::OUT_LIGHTS + 4*2)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 242.635), module, _8vert::OUT_LIGHTS + 5*2)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 281.076), module, _8vert::OUT_LIGHTS + 6*2)); | |||||
addChild(createLight<TinyLight<GreenRedLight>>(Vec(107.702, 319.521), module, _8vert::OUT_LIGHTS + 7*2)); | |||||
} | } | ||||
@@ -31,74 +31,78 @@ struct ADSR : Module { | |||||
}; | }; | ||||
bool decaying = false; | bool decaying = false; | ||||
float env = 0.0f; | |||||
SchmittTrigger trigger; | |||||
ADSR() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||||
void step() override; | |||||
}; | |||||
float env = 0.f; | |||||
dsp::SchmittTrigger trigger; | |||||
ADSR() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
params[ATTACK_PARAM].config(0.f, 1.f, 0.5f); | |||||
params[DECAY_PARAM].config(0.f, 1.f, 0.5f); | |||||
params[SUSTAIN_PARAM].config(0.f, 1.f, 0.5f); | |||||
params[RELEASE_PARAM].config(0.f, 1.f, 0.5f); | |||||
} | |||||
void ADSR::step() { | |||||
float attack = clamp(params[ATTACK_PARAM].value + inputs[ATTACK_INPUT].value / 10.0f, 0.0f, 1.0f); | |||||
float decay = clamp(params[DECAY_PARAM].value + inputs[DECAY_INPUT].value / 10.0f, 0.0f, 1.0f); | |||||
float sustain = clamp(params[SUSTAIN_PARAM].value + inputs[SUSTAIN_INPUT].value / 10.0f, 0.0f, 1.0f); | |||||
float release = clamp(params[RELEASE_PARAM].value + inputs[RELEASE_INPUT].value / 10.0f, 0.0f, 1.0f); | |||||
// Gate and trigger | |||||
bool gated = inputs[GATE_INPUT].value >= 1.0f; | |||||
if (trigger.process(inputs[TRIG_INPUT].value)) | |||||
decaying = false; | |||||
const float base = 20000.0f; | |||||
const float maxTime = 10.0f; | |||||
if (gated) { | |||||
if (decaying) { | |||||
// Decay | |||||
if (decay < 1e-4) { | |||||
env = sustain; | |||||
void step() override { | |||||
float attack = clamp(params[ATTACK_PARAM].value + inputs[ATTACK_INPUT].value / 10.f, 0.f, 1.f); | |||||
float decay = clamp(params[DECAY_PARAM].value + inputs[DECAY_INPUT].value / 10.f, 0.f, 1.f); | |||||
float sustain = clamp(params[SUSTAIN_PARAM].value + inputs[SUSTAIN_INPUT].value / 10.f, 0.f, 1.f); | |||||
float release = clamp(params[RELEASE_PARAM].value + inputs[RELEASE_INPUT].value / 10.f, 0.f, 1.f); | |||||
// Gate and trigger | |||||
bool gated = inputs[GATE_INPUT].value >= 1.f; | |||||
if (trigger.process(inputs[TRIG_INPUT].value)) | |||||
decaying = false; | |||||
const float base = 20000.f; | |||||
const float maxTime = 10.f; | |||||
if (gated) { | |||||
if (decaying) { | |||||
// Decay | |||||
if (decay < 1e-4) { | |||||
env = sustain; | |||||
} | |||||
else { | |||||
env += std::pow(base, 1 - decay) / maxTime * (sustain - env) * app()->engine->getSampleTime(); | |||||
} | |||||
} | } | ||||
else { | else { | ||||
env += powf(base, 1 - decay) / maxTime * (sustain - env) * engineGetSampleTime(); | |||||
// Attack | |||||
// Skip ahead if attack is all the way down (infinitely fast) | |||||
if (attack < 1e-4) { | |||||
env = 1.f; | |||||
} | |||||
else { | |||||
env += std::pow(base, 1 - attack) / maxTime * (1.01f - env) * app()->engine->getSampleTime(); | |||||
} | |||||
if (env >= 1.f) { | |||||
env = 1.f; | |||||
decaying = true; | |||||
} | |||||
} | } | ||||
} | } | ||||
else { | else { | ||||
// Attack | |||||
// Skip ahead if attack is all the way down (infinitely fast) | |||||
if (attack < 1e-4) { | |||||
env = 1.0f; | |||||
// Release | |||||
if (release < 1e-4) { | |||||
env = 0.f; | |||||
} | } | ||||
else { | else { | ||||
env += powf(base, 1 - attack) / maxTime * (1.01f - env) * engineGetSampleTime(); | |||||
env += std::pow(base, 1 - release) / maxTime * (0.f - env) * app()->engine->getSampleTime(); | |||||
} | } | ||||
if (env >= 1.0f) { | |||||
env = 1.0f; | |||||
decaying = true; | |||||
} | |||||
} | |||||
} | |||||
else { | |||||
// Release | |||||
if (release < 1e-4) { | |||||
env = 0.0f; | |||||
decaying = false; | |||||
} | } | ||||
else { | |||||
env += powf(base, 1 - release) / maxTime * (0.0f - env) * engineGetSampleTime(); | |||||
} | |||||
decaying = false; | |||||
} | |||||
bool sustaining = isNear(env, sustain, 1e-3); | |||||
bool resting = isNear(env, 0.0f, 1e-3); | |||||
bool sustaining = isNear(env, sustain, 1e-3); | |||||
bool resting = isNear(env, 0.f, 1e-3); | |||||
outputs[ENVELOPE_OUTPUT].value = 10.0f * env; | |||||
outputs[ENVELOPE_OUTPUT].value = 10.f * env; | |||||
// Lights | |||||
lights[ATTACK_LIGHT].value = (gated && !decaying) ? 1.0f : 0.0f; | |||||
lights[DECAY_LIGHT].value = (gated && decaying && !sustaining) ? 1.0f : 0.0f; | |||||
lights[SUSTAIN_LIGHT].value = (gated && decaying && sustaining) ? 1.0f : 0.0f; | |||||
lights[RELEASE_LIGHT].value = (!gated && !resting) ? 1.0f : 0.0f; | |||||
} | |||||
// Lights | |||||
lights[ATTACK_LIGHT].value = (gated && !decaying) ? 1.f : 0.f; | |||||
lights[DECAY_LIGHT].value = (gated && decaying && !sustaining) ? 1.f : 0.f; | |||||
lights[SUSTAIN_LIGHT].value = (gated && decaying && sustaining) ? 1.f : 0.f; | |||||
lights[RELEASE_LIGHT].value = (!gated && !resting) ? 1.f : 0.f; | |||||
} | |||||
}; | |||||
struct ADSRWidget : ModuleWidget { | struct ADSRWidget : ModuleWidget { | ||||
@@ -106,26 +110,26 @@ struct ADSRWidget : ModuleWidget { | |||||
}; | }; | ||||
ADSRWidget::ADSRWidget(ADSR *module) : ModuleWidget(module) { | ADSRWidget::ADSRWidget(ADSR *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/ADSR.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/ADSR.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | addChild(createWidget<ScrewSilver>(Vec(15, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | addChild(createWidget<ScrewSilver>(Vec(15, 365))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365))); | ||||
addParam(createParam<RoundLargeBlackKnob>(Vec(62, 57), module, ADSR::ATTACK_PARAM, 0.0f, 1.0f, 0.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(62, 124), module, ADSR::DECAY_PARAM, 0.0f, 1.0f, 0.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(62, 191), module, ADSR::SUSTAIN_PARAM, 0.0f, 1.0f, 0.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(62, 257), module, ADSR::RELEASE_PARAM, 0.0f, 1.0f, 0.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(62, 57), module, ADSR::ATTACK_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(62, 124), module, ADSR::DECAY_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(62, 191), module, ADSR::SUSTAIN_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(62, 257), module, ADSR::RELEASE_PARAM)); | |||||
addInput(createPort<PJ301MPort>(Vec(9, 63), PortWidget::INPUT, module, ADSR::ATTACK_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(9, 129), PortWidget::INPUT, module, ADSR::DECAY_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(9, 196), PortWidget::INPUT, module, ADSR::SUSTAIN_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(9, 263), PortWidget::INPUT, module, ADSR::RELEASE_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(9, 63), module, ADSR::ATTACK_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(9, 129), module, ADSR::DECAY_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(9, 196), module, ADSR::SUSTAIN_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(9, 263), module, ADSR::RELEASE_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(9, 320), PortWidget::INPUT, module, ADSR::GATE_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(48, 320), PortWidget::INPUT, module, ADSR::TRIG_INPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(87, 320), PortWidget::OUTPUT, module, ADSR::ENVELOPE_OUTPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(9, 320), module, ADSR::GATE_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(48, 320), module, ADSR::TRIG_INPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(87, 320), module, ADSR::ENVELOPE_OUTPUT)); | |||||
addChild(createLight<SmallLight<RedLight>>(Vec(94, 41), module, ADSR::ATTACK_LIGHT)); | addChild(createLight<SmallLight<RedLight>>(Vec(94, 41), module, ADSR::ATTACK_LIGHT)); | ||||
addChild(createLight<SmallLight<RedLight>>(Vec(94, 109), module, ADSR::DECAY_LIGHT)); | addChild(createLight<SmallLight<RedLight>>(Vec(94, 109), module, ADSR::DECAY_LIGHT)); | ||||
@@ -25,14 +25,20 @@ struct Delay : Module { | |||||
NUM_OUTPUTS | NUM_OUTPUTS | ||||
}; | }; | ||||
DoubleRingBuffer<float, HISTORY_SIZE> historyBuffer; | |||||
DoubleRingBuffer<float, 16> outBuffer; | |||||
dsp::DoubleRingBuffer<float, HISTORY_SIZE> historyBuffer; | |||||
dsp::DoubleRingBuffer<float, 16> outBuffer; | |||||
SRC_STATE *src; | SRC_STATE *src; | ||||
float lastWet = 0.0f; | float lastWet = 0.0f; | ||||
RCFilter lowpassFilter; | |||||
RCFilter highpassFilter; | |||||
dsp::RCFilter lowpassFilter; | |||||
dsp::RCFilter highpassFilter; | |||||
Delay() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | |||||
params[TIME_PARAM].config(0.0f, 1.0f, 0.5f); | |||||
params[FEEDBACK_PARAM].config(0.0f, 1.0f, 0.5f); | |||||
params[COLOR_PARAM].config(0.0f, 1.0f, 0.5f); | |||||
params[MIX_PARAM].config(0.0f, 1.0f, 0.5f); | |||||
Delay() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | |||||
src = src_new(SRC_SINC_FASTEST, 1, NULL); | src = src_new(SRC_SINC_FASTEST, 1, NULL); | ||||
assert(src); | assert(src); | ||||
} | } | ||||
@@ -41,96 +47,91 @@ struct Delay : Module { | |||||
src_delete(src); | src_delete(src); | ||||
} | } | ||||
void step() override; | |||||
}; | |||||
void Delay::step() { | |||||
// Get input to delay block | |||||
float in = inputs[IN_INPUT].value; | |||||
float feedback = clamp(params[FEEDBACK_PARAM].value + inputs[FEEDBACK_INPUT].value / 10.0f, 0.0f, 1.0f); | |||||
float dry = in + lastWet * feedback; | |||||
void step() override { | |||||
// Get input to delay block | |||||
float in = inputs[IN_INPUT].value; | |||||
float feedback = clamp(params[FEEDBACK_PARAM].value + inputs[FEEDBACK_INPUT].value / 10.0f, 0.0f, 1.0f); | |||||
float dry = in + lastWet * feedback; | |||||
// Compute delay time in seconds | |||||
float delay = 1e-3 * powf(10.0f / 1e-3, clamp(params[TIME_PARAM].value + inputs[TIME_INPUT].value / 10.0f, 0.0f, 1.0f)); | |||||
// Number of delay samples | |||||
float index = delay * engineGetSampleRate(); | |||||
// Compute delay time in seconds | |||||
float delay = 1e-3 * std::pow(10.0f / 1e-3, clamp(params[TIME_PARAM].value + inputs[TIME_INPUT].value / 10.0f, 0.0f, 1.0f)); | |||||
// Number of delay samples | |||||
float index = delay * app()->engine->getSampleRate(); | |||||
// Push dry sample into history buffer | |||||
if (!historyBuffer.full()) { | |||||
historyBuffer.push(dry); | |||||
} | |||||
// How many samples do we need consume to catch up? | |||||
float consume = index - historyBuffer.size(); | |||||
// Push dry sample into history buffer | |||||
if (!historyBuffer.full()) { | |||||
historyBuffer.push(dry); | |||||
} | |||||
if (outBuffer.empty()) { | |||||
double ratio = 1.f; | |||||
if (fabsf(consume) >= 16.f) { | |||||
ratio = powf(10.f, clamp(consume / 10000.f, -1.f, 1.f)); | |||||
// How many samples do we need consume to catch up? | |||||
float consume = index - historyBuffer.size(); | |||||
if (outBuffer.empty()) { | |||||
double ratio = 1.f; | |||||
if (std::abs(consume) >= 16.f) { | |||||
ratio = std::pow(10.f, clamp(consume / 10000.f, -1.f, 1.f)); | |||||
} | |||||
SRC_DATA srcData; | |||||
srcData.data_in = (const float*) historyBuffer.startData(); | |||||
srcData.data_out = (float*) outBuffer.endData(); | |||||
srcData.input_frames = std::min((int) historyBuffer.size(), 16); | |||||
srcData.output_frames = outBuffer.capacity(); | |||||
srcData.end_of_input = false; | |||||
srcData.src_ratio = ratio; | |||||
src_process(src, &srcData); | |||||
historyBuffer.startIncr(srcData.input_frames_used); | |||||
outBuffer.endIncr(srcData.output_frames_gen); | |||||
} | } | ||||
SRC_DATA srcData; | |||||
srcData.data_in = (const float*) historyBuffer.startData(); | |||||
srcData.data_out = (float*) outBuffer.endData(); | |||||
srcData.input_frames = min(historyBuffer.size(), 16); | |||||
srcData.output_frames = outBuffer.capacity(); | |||||
srcData.end_of_input = false; | |||||
srcData.src_ratio = ratio; | |||||
src_process(src, &srcData); | |||||
historyBuffer.startIncr(srcData.input_frames_used); | |||||
outBuffer.endIncr(srcData.output_frames_gen); | |||||
} | |||||
float wet = 0.0f; | |||||
if (!outBuffer.empty()) { | |||||
wet = outBuffer.shift(); | |||||
} | |||||
float wet = 0.0f; | |||||
if (!outBuffer.empty()) { | |||||
wet = outBuffer.shift(); | |||||
// Apply color to delay wet output | |||||
// TODO Make it sound better | |||||
float color = clamp(params[COLOR_PARAM].value + inputs[COLOR_INPUT].value / 10.0f, 0.0f, 1.0f); | |||||
float lowpassFreq = 10000.0f * std::pow(10.0f, clamp(2.0f*color, 0.0f, 1.0f)); | |||||
lowpassFilter.setCutoff(lowpassFreq / app()->engine->getSampleRate()); | |||||
lowpassFilter.process(wet); | |||||
wet = lowpassFilter.lowpass(); | |||||
float highpassFreq = 10.0f * std::pow(100.0f, clamp(2.0f*color - 1.0f, 0.0f, 1.0f)); | |||||
highpassFilter.setCutoff(highpassFreq / app()->engine->getSampleRate()); | |||||
highpassFilter.process(wet); | |||||
wet = highpassFilter.highpass(); | |||||
lastWet = wet; | |||||
float mix = clamp(params[MIX_PARAM].value + inputs[MIX_INPUT].value / 10.0f, 0.0f, 1.0f); | |||||
float out = crossfade(in, wet, mix); | |||||
outputs[OUT_OUTPUT].value = out; | |||||
} | } | ||||
// Apply color to delay wet output | |||||
// TODO Make it sound better | |||||
float color = clamp(params[COLOR_PARAM].value + inputs[COLOR_INPUT].value / 10.0f, 0.0f, 1.0f); | |||||
float lowpassFreq = 10000.0f * powf(10.0f, clamp(2.0f*color, 0.0f, 1.0f)); | |||||
lowpassFilter.setCutoff(lowpassFreq / engineGetSampleRate()); | |||||
lowpassFilter.process(wet); | |||||
wet = lowpassFilter.lowpass(); | |||||
float highpassFreq = 10.0f * powf(100.0f, clamp(2.0f*color - 1.0f, 0.0f, 1.0f)); | |||||
highpassFilter.setCutoff(highpassFreq / engineGetSampleRate()); | |||||
highpassFilter.process(wet); | |||||
wet = highpassFilter.highpass(); | |||||
lastWet = wet; | |||||
float mix = clamp(params[MIX_PARAM].value + inputs[MIX_INPUT].value / 10.0f, 0.0f, 1.0f); | |||||
float out = crossfade(in, wet, mix); | |||||
outputs[OUT_OUTPUT].value = out; | |||||
} | |||||
}; | |||||
struct DelayWidget : ModuleWidget { | struct DelayWidget : ModuleWidget { | ||||
DelayWidget(Delay *module); | |||||
DelayWidget(Delay *module) : ModuleWidget(module) { | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/Delay.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | |||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | |||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365))); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(67, 57), module, Delay::TIME_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(67, 123), module, Delay::FEEDBACK_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(67, 190), module, Delay::COLOR_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(67, 257), module, Delay::MIX_PARAM)); | |||||
addInput(createInput<PJ301MPort>(Vec(14, 63), module, Delay::TIME_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(14, 129), module, Delay::FEEDBACK_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(14, 196), module, Delay::COLOR_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(14, 263), module, Delay::MIX_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(14, 320), module, Delay::IN_INPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(73, 320), module, Delay::OUT_OUTPUT)); | |||||
} | |||||
}; | }; | ||||
DelayWidget::DelayWidget(Delay *module) : ModuleWidget(module) { | |||||
setPanel(SVG::load(assetPlugin(plugin, "res/Delay.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | |||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | |||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365))); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(67, 57), module, Delay::TIME_PARAM, 0.0f, 1.0f, 0.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(67, 123), module, Delay::FEEDBACK_PARAM, 0.0f, 1.0f, 0.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(67, 190), module, Delay::COLOR_PARAM, 0.0f, 1.0f, 0.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(67, 257), module, Delay::MIX_PARAM, 0.0f, 1.0f, 0.5f)); | |||||
addInput(createPort<PJ301MPort>(Vec(14, 63), PortWidget::INPUT, module, Delay::TIME_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(14, 129), PortWidget::INPUT, module, Delay::FEEDBACK_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(14, 196), PortWidget::INPUT, module, Delay::COLOR_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(14, 263), PortWidget::INPUT, module, Delay::MIX_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(14, 320), PortWidget::INPUT, module, Delay::IN_INPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(73, 320), PortWidget::OUTPUT, module, Delay::OUT_OUTPUT)); | |||||
} | |||||
Model *modelDelay = createModel<Delay, DelayWidget>("Delay"); | Model *modelDelay = createModel<Delay, DelayWidget>("Delay"); |
@@ -5,8 +5,6 @@ Plugin *plugin; | |||||
void init(rack::Plugin *p) { | void init(rack::Plugin *p) { | ||||
plugin = p; | plugin = p; | ||||
p->slug = TOSTRING(SLUG); | |||||
p->version = TOSTRING(VERSION); | |||||
p->addModel(modelVCO); | p->addModel(modelVCO); | ||||
p->addModel(modelVCO2); | p->addModel(modelVCO2); | ||||
@@ -1,4 +1,5 @@ | |||||
#include "rack0.hpp" | |||||
#include "rack.hpp" | |||||
#include "componentlibrary.hpp" | |||||
using namespace rack; | using namespace rack; | ||||
@@ -2,63 +2,63 @@ | |||||
struct LowFrequencyOscillator { | struct LowFrequencyOscillator { | ||||
float phase = 0.0f; | |||||
float phase = 0.f; | |||||
float pw = 0.5f; | float pw = 0.5f; | ||||
float freq = 1.0f; | |||||
float freq = 1.f; | |||||
bool offset = false; | bool offset = false; | ||||
bool invert = false; | bool invert = false; | ||||
SchmittTrigger resetTrigger; | |||||
dsp::SchmittTrigger resetTrigger; | |||||
LowFrequencyOscillator() {} | LowFrequencyOscillator() {} | ||||
void setPitch(float pitch) { | void setPitch(float pitch) { | ||||
pitch = fminf(pitch, 10.0f); | |||||
freq = powf(2.0f, pitch); | |||||
pitch = fminf(pitch, 10.f); | |||||
freq = powf(2.f, pitch); | |||||
} | } | ||||
void setPulseWidth(float pw_) { | void setPulseWidth(float pw_) { | ||||
const float pwMin = 0.01f; | const float pwMin = 0.01f; | ||||
pw = clamp(pw_, pwMin, 1.0f - pwMin); | |||||
pw = clamp(pw_, pwMin, 1.f - pwMin); | |||||
} | } | ||||
void setReset(float reset) { | void setReset(float reset) { | ||||
if (resetTrigger.process(reset / 0.01f)) { | if (resetTrigger.process(reset / 0.01f)) { | ||||
phase = 0.0f; | |||||
phase = 0.f; | |||||
} | } | ||||
} | } | ||||
void step(float dt) { | void step(float dt) { | ||||
float deltaPhase = fminf(freq * dt, 0.5f); | float deltaPhase = fminf(freq * dt, 0.5f); | ||||
phase += deltaPhase; | phase += deltaPhase; | ||||
if (phase >= 1.0f) | |||||
phase -= 1.0f; | |||||
if (phase >= 1.f) | |||||
phase -= 1.f; | |||||
} | } | ||||
float sin() { | float sin() { | ||||
if (offset) | if (offset) | ||||
return 1.0f - cosf(2*M_PI * phase) * (invert ? -1.0f : 1.0f); | |||||
return 1.f - std::cos(2*M_PI * phase) * (invert ? -1.f : 1.f); | |||||
else | else | ||||
return sinf(2*M_PI * phase) * (invert ? -1.0f : 1.0f); | |||||
return std::sin(2*M_PI * phase) * (invert ? -1.f : 1.f); | |||||
} | } | ||||
float tri(float x) { | float tri(float x) { | ||||
return 4.0f * fabsf(x - roundf(x)); | |||||
return 4.f * std::abs(x - std::round(x)); | |||||
} | } | ||||
float tri() { | float tri() { | ||||
if (offset) | if (offset) | ||||
return tri(invert ? phase - 0.5f : phase); | return tri(invert ? phase - 0.5f : phase); | ||||
else | else | ||||
return -1.0f + tri(invert ? phase - 0.25f : phase - 0.75f); | |||||
return -1.f + tri(invert ? phase - 0.25f : phase - 0.75f); | |||||
} | } | ||||
float saw(float x) { | float saw(float x) { | ||||
return 2.0f * (x - roundf(x)); | |||||
return 2.f * (x - std::round(x)); | |||||
} | } | ||||
float saw() { | float saw() { | ||||
if (offset) | if (offset) | ||||
return invert ? 2.0f * (1.0f - phase) : 2.0f * phase; | |||||
return invert ? 2.f * (1.f - phase) : 2.f * phase; | |||||
else | else | ||||
return saw(phase) * (invert ? -1.0f : 1.0f); | |||||
return saw(phase) * (invert ? -1.f : 1.f); | |||||
} | } | ||||
float sqr() { | float sqr() { | ||||
float sqr = (phase < pw) ^ invert ? 1.0f : -1.0f; | |||||
return offset ? sqr + 1.0f : sqr; | |||||
float sqr = (phase < pw) ^ invert ? 1.f : -1.f; | |||||
return offset ? sqr + 1.f : sqr; | |||||
} | } | ||||
float light() { | float light() { | ||||
return sinf(2*M_PI * phase); | |||||
return std::sin(2*M_PI * phase); | |||||
} | } | ||||
}; | }; | ||||
@@ -96,27 +96,36 @@ struct LFO : Module { | |||||
LowFrequencyOscillator oscillator; | LowFrequencyOscillator oscillator; | ||||
LFO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||||
void step() override; | |||||
}; | |||||
LFO() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
params[OFFSET_PARAM].config(0.f, 1.f, 1.f); | |||||
params[INVERT_PARAM].config(0.f, 1.f, 1.f); | |||||
params[FREQ_PARAM].config(-8.f, 10.f, 1.f); | |||||
params[FM1_PARAM].config(0.f, 1.f, 0.f); | |||||
params[PW_PARAM].config(0.f, 1.f, 0.5f); | |||||
params[FM2_PARAM].config(0.f, 1.f, 0.f); | |||||
params[PWM_PARAM].config(0.f, 1.f, 0.f); | |||||
} | |||||
void LFO::step() { | |||||
oscillator.setPitch(params[FREQ_PARAM].value + params[FM1_PARAM].value * inputs[FM1_INPUT].value + params[FM2_PARAM].value * inputs[FM2_INPUT].value); | |||||
oscillator.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.0f); | |||||
oscillator.offset = (params[OFFSET_PARAM].value > 0.0f); | |||||
oscillator.invert = (params[INVERT_PARAM].value <= 0.0f); | |||||
oscillator.step(engineGetSampleTime()); | |||||
oscillator.setReset(inputs[RESET_INPUT].value); | |||||
void step() override { | |||||
oscillator.setPitch(params[FREQ_PARAM].value + params[FM1_PARAM].value * inputs[FM1_INPUT].value + params[FM2_PARAM].value * inputs[FM2_INPUT].value); | |||||
oscillator.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.f); | |||||
oscillator.offset = (params[OFFSET_PARAM].value > 0.f); | |||||
oscillator.invert = (params[INVERT_PARAM].value <= 0.f); | |||||
oscillator.step(app()->engine->getSampleTime()); | |||||
oscillator.setReset(inputs[RESET_INPUT].value); | |||||
outputs[SIN_OUTPUT].value = 5.f * oscillator.sin(); | |||||
outputs[TRI_OUTPUT].value = 5.f * oscillator.tri(); | |||||
outputs[SAW_OUTPUT].value = 5.f * oscillator.saw(); | |||||
outputs[SQR_OUTPUT].value = 5.f * oscillator.sqr(); | |||||
lights[PHASE_POS_LIGHT].setBrightnessSmooth(std::max(0.f, oscillator.light())); | |||||
lights[PHASE_NEG_LIGHT].setBrightnessSmooth(std::max(0.f, -oscillator.light())); | |||||
} | |||||
outputs[SIN_OUTPUT].value = 5.0f * oscillator.sin(); | |||||
outputs[TRI_OUTPUT].value = 5.0f * oscillator.tri(); | |||||
outputs[SAW_OUTPUT].value = 5.0f * oscillator.saw(); | |||||
outputs[SQR_OUTPUT].value = 5.0f * oscillator.sqr(); | |||||
}; | |||||
lights[PHASE_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0f, oscillator.light())); | |||||
lights[PHASE_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0f, -oscillator.light())); | |||||
} | |||||
struct LFOWidget : ModuleWidget { | struct LFOWidget : ModuleWidget { | ||||
@@ -124,31 +133,31 @@ struct LFOWidget : ModuleWidget { | |||||
}; | }; | ||||
LFOWidget::LFOWidget(LFO *module) : ModuleWidget(module) { | LFOWidget::LFOWidget(LFO *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/LFO-1.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/LFO-1.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | addChild(createWidget<ScrewSilver>(Vec(15, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | addChild(createWidget<ScrewSilver>(Vec(15, 365))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365))); | ||||
addParam(createParam<CKSS>(Vec(15, 77), module, LFO::OFFSET_PARAM, 0.0f, 1.0f, 1.0f)); | |||||
addParam(createParam<CKSS>(Vec(119, 77), module, LFO::INVERT_PARAM, 0.0f, 1.0f, 1.0f)); | |||||
addParam(createParam<CKSS>(Vec(15, 77), module, LFO::OFFSET_PARAM)); | |||||
addParam(createParam<CKSS>(Vec(119, 77), module, LFO::INVERT_PARAM)); | |||||
addParam(createParam<RoundHugeBlackKnob>(Vec(47, 61), module, LFO::FREQ_PARAM, -8.0f, 10.0f, 1.0f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(23, 143), module, LFO::FM1_PARAM, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(91, 143), module, LFO::PW_PARAM, 0.0f, 1.0f, 0.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(23, 208), module, LFO::FM2_PARAM, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(91, 208), module, LFO::PWM_PARAM, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundHugeBlackKnob>(Vec(47, 61), module, LFO::FREQ_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(23, 143), module, LFO::FM1_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(91, 143), module, LFO::PW_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(23, 208), module, LFO::FM2_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(91, 208), module, LFO::PWM_PARAM)); | |||||
addInput(createPort<PJ301MPort>(Vec(11, 276), PortWidget::INPUT, module, LFO::FM1_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(45, 276), PortWidget::INPUT, module, LFO::FM2_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(80, 276), PortWidget::INPUT, module, LFO::RESET_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(114, 276), PortWidget::INPUT, module, LFO::PW_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(11, 276), module, LFO::FM1_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(45, 276), module, LFO::FM2_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(80, 276), module, LFO::RESET_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(114, 276), module, LFO::PW_INPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(11, 320), PortWidget::OUTPUT, module, LFO::SIN_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(45, 320), PortWidget::OUTPUT, module, LFO::TRI_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(80, 320), PortWidget::OUTPUT, module, LFO::SAW_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(114, 320), PortWidget::OUTPUT, module, LFO::SQR_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(11, 320), module, LFO::SIN_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(45, 320), module, LFO::TRI_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(80, 320), module, LFO::SAW_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(114, 320), module, LFO::SQR_OUTPUT)); | |||||
addChild(createLight<SmallLight<GreenRedLight>>(Vec(99, 42.5f), module, LFO::PHASE_POS_LIGHT)); | addChild(createLight<SmallLight<GreenRedLight>>(Vec(99, 42.5f), module, LFO::PHASE_POS_LIGHT)); | ||||
} | } | ||||
@@ -184,32 +193,37 @@ struct LFO2 : Module { | |||||
LowFrequencyOscillator oscillator; | LowFrequencyOscillator oscillator; | ||||
LFO2() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||||
void step() override; | |||||
}; | |||||
LFO2() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
params[OFFSET_PARAM].config(0.f, 1.f, 1.f); | |||||
params[INVERT_PARAM].config(0.f, 1.f, 1.f); | |||||
params[FREQ_PARAM].config(-8.f, 10.f, 1.f); | |||||
params[WAVE_PARAM].config(0.f, 3.f, 1.5f); | |||||
params[FM_PARAM].config(0.f, 1.f, 0.5f); | |||||
} | |||||
void step() override { | |||||
oscillator.setPitch(params[FREQ_PARAM].value + params[FM_PARAM].value * inputs[FM_INPUT].value); | |||||
oscillator.offset = (params[OFFSET_PARAM].value > 0.f); | |||||
oscillator.invert = (params[INVERT_PARAM].value <= 0.f); | |||||
oscillator.step(app()->engine->getSampleTime()); | |||||
oscillator.setReset(inputs[RESET_INPUT].value); | |||||
float wave = params[WAVE_PARAM].value + inputs[WAVE_INPUT].value; | |||||
wave = clamp(wave, 0.f, 3.f); | |||||
float interp; | |||||
if (wave < 1.f) | |||||
interp = crossfade(oscillator.sin(), oscillator.tri(), wave); | |||||
else if (wave < 2.f) | |||||
interp = crossfade(oscillator.tri(), oscillator.saw(), wave - 1.f); | |||||
else | |||||
interp = crossfade(oscillator.saw(), oscillator.sqr(), wave - 2.f); | |||||
outputs[INTERP_OUTPUT].value = 5.f * interp; | |||||
void LFO2::step() { | |||||
oscillator.setPitch(params[FREQ_PARAM].value + params[FM_PARAM].value * inputs[FM_INPUT].value); | |||||
oscillator.offset = (params[OFFSET_PARAM].value > 0.0f); | |||||
oscillator.invert = (params[INVERT_PARAM].value <= 0.0f); | |||||
oscillator.step(engineGetSampleTime()); | |||||
oscillator.setReset(inputs[RESET_INPUT].value); | |||||
float wave = params[WAVE_PARAM].value + inputs[WAVE_INPUT].value; | |||||
wave = clamp(wave, 0.0f, 3.0f); | |||||
float interp; | |||||
if (wave < 1.0f) | |||||
interp = crossfade(oscillator.sin(), oscillator.tri(), wave); | |||||
else if (wave < 2.0f) | |||||
interp = crossfade(oscillator.tri(), oscillator.saw(), wave - 1.0f); | |||||
else | |||||
interp = crossfade(oscillator.saw(), oscillator.sqr(), wave - 2.0f); | |||||
outputs[INTERP_OUTPUT].value = 5.0f * interp; | |||||
lights[PHASE_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0f, oscillator.light())); | |||||
lights[PHASE_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0f, -oscillator.light())); | |||||
} | |||||
lights[PHASE_POS_LIGHT].setBrightnessSmooth(std::max(0.f, oscillator.light())); | |||||
lights[PHASE_NEG_LIGHT].setBrightnessSmooth(std::max(0.f, -oscillator.light())); | |||||
} | |||||
}; | |||||
struct LFO2Widget : ModuleWidget { | struct LFO2Widget : ModuleWidget { | ||||
@@ -217,25 +231,25 @@ struct LFO2Widget : ModuleWidget { | |||||
}; | }; | ||||
LFO2Widget::LFO2Widget(LFO2 *module) : ModuleWidget(module) { | LFO2Widget::LFO2Widget(LFO2 *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/LFO-2.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/LFO-2.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | addChild(createWidget<ScrewSilver>(Vec(15, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | addChild(createWidget<ScrewSilver>(Vec(15, 365))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365))); | ||||
addParam(createParam<CKSS>(Vec(62, 150), module, LFO2::OFFSET_PARAM, 0.0f, 1.0f, 1.0f)); | |||||
addParam(createParam<CKSS>(Vec(62, 215), module, LFO2::INVERT_PARAM, 0.0f, 1.0f, 1.0f)); | |||||
addParam(createParam<CKSS>(Vec(62, 150), module, LFO2::OFFSET_PARAM)); | |||||
addParam(createParam<CKSS>(Vec(62, 215), module, LFO2::INVERT_PARAM)); | |||||
addParam(createParam<RoundHugeBlackKnob>(Vec(18, 60), module, LFO2::FREQ_PARAM, -8.0f, 10.0f, 1.0f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(11, 142), module, LFO2::WAVE_PARAM, 0.0f, 3.0f, 1.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(11, 207), module, LFO2::FM_PARAM, 0.0f, 1.0f, 0.5f)); | |||||
addParam(createParam<RoundHugeBlackKnob>(Vec(18, 60), module, LFO2::FREQ_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(11, 142), module, LFO2::WAVE_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(11, 207), module, LFO2::FM_PARAM)); | |||||
addInput(createPort<PJ301MPort>(Vec(11, 276), PortWidget::INPUT, module, LFO2::FM_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(54, 276), PortWidget::INPUT, module, LFO2::RESET_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(11, 319), PortWidget::INPUT, module, LFO2::WAVE_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(11, 276), module, LFO2::FM_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(54, 276), module, LFO2::RESET_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(11, 319), module, LFO2::WAVE_INPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(54, 319), PortWidget::OUTPUT, module, LFO2::INTERP_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(54, 319), module, LFO2::INTERP_OUTPUT)); | |||||
addChild(createLight<SmallLight<GreenRedLight>>(Vec(68, 42.5f), module, LFO2::PHASE_POS_LIGHT)); | addChild(createLight<SmallLight<GreenRedLight>>(Vec(68, 42.5f), module, LFO2::PHASE_POS_LIGHT)); | ||||
} | } | ||||
@@ -23,12 +23,28 @@ struct Mutes : Module { | |||||
}; | }; | ||||
bool state[NUM_CHANNELS]; | bool state[NUM_CHANNELS]; | ||||
SchmittTrigger muteTrigger[NUM_CHANNELS]; | |||||
dsp::SchmittTrigger muteTrigger[NUM_CHANNELS]; | |||||
Mutes() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
for (int i = 0; i < NUM_CHANNELS; i++) { | |||||
params[MUTE_PARAM + i].config(0.0, 1.0, 0.0, string::f("Ch %d mute", i)); | |||||
} | |||||
Mutes() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||||
onReset(); | onReset(); | ||||
} | } | ||||
void step() override; | |||||
void step() override { | |||||
float out = 0.f; | |||||
for (int i = 0; i < NUM_CHANNELS; i++) { | |||||
if (muteTrigger[i].process(params[MUTE_PARAM + i].value)) | |||||
state[i] ^= true; | |||||
if (inputs[IN_INPUT + i].active) | |||||
out = inputs[IN_INPUT + i].value; | |||||
outputs[OUT_OUTPUT + i].value = state[i] ? out : 0.f; | |||||
lights[MUTE_LIGHT + i].setBrightness(state[i] ? 0.9f : 0.f); | |||||
} | |||||
} | |||||
void onReset() override { | void onReset() override { | ||||
for (int i = 0; i < NUM_CHANNELS; i++) { | for (int i = 0; i < NUM_CHANNELS; i++) { | ||||
@@ -37,7 +53,7 @@ struct Mutes : Module { | |||||
} | } | ||||
void onRandomize() override { | void onRandomize() override { | ||||
for (int i = 0; i < NUM_CHANNELS; i++) { | for (int i = 0; i < NUM_CHANNELS; i++) { | ||||
state[i] = (randomUniform() < 0.5f); | |||||
state[i] = (random::uniform() < 0.5f); | |||||
} | } | ||||
} | } | ||||
@@ -52,6 +68,7 @@ struct Mutes : Module { | |||||
json_object_set_new(rootJ, "states", statesJ); | json_object_set_new(rootJ, "states", statesJ); | ||||
return rootJ; | return rootJ; | ||||
} | } | ||||
void dataFromJson(json_t *rootJ) override { | void dataFromJson(json_t *rootJ) override { | ||||
// states | // states | ||||
json_t *statesJ = json_object_get(rootJ, "states"); | json_t *statesJ = json_object_get(rootJ, "states"); | ||||
@@ -65,23 +82,11 @@ struct Mutes : Module { | |||||
} | } | ||||
}; | }; | ||||
void Mutes::step() { | |||||
float out = 0.0f; | |||||
for (int i = 0; i < NUM_CHANNELS; i++) { | |||||
if (muteTrigger[i].process(params[MUTE_PARAM + i].value)) | |||||
state[i] ^= true; | |||||
if (inputs[IN_INPUT + i].active) | |||||
out = inputs[IN_INPUT + i].value; | |||||
outputs[OUT_OUTPUT + i].value = state[i] ? out : 0.0f; | |||||
lights[MUTE_LIGHT + i].setBrightness(state[i] ? 0.9f : 0.0f); | |||||
} | |||||
} | |||||
template <typename BASE> | template <typename BASE> | ||||
struct MuteLight : BASE { | struct MuteLight : BASE { | ||||
MuteLight() { | MuteLight() { | ||||
this->box.size = mm2px(Vec(6.0f, 6.0f)); | |||||
this->box.size = mm2px(Vec(6.f, 6.f)); | |||||
} | } | ||||
}; | }; | ||||
@@ -91,45 +96,45 @@ struct MutesWidget : ModuleWidget { | |||||
}; | }; | ||||
MutesWidget::MutesWidget(Mutes *module) : ModuleWidget(module) { | MutesWidget::MutesWidget(Mutes *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/Mutes.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/Mutes.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | addChild(createWidget<ScrewSilver>(Vec(15, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | addChild(createWidget<ScrewSilver>(Vec(15, 365))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365))); | ||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 18.165)), module, Mutes::MUTE_PARAM + 0, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 28.164)), module, Mutes::MUTE_PARAM + 1, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 38.164)), module, Mutes::MUTE_PARAM + 2, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 48.165)), module, Mutes::MUTE_PARAM + 3, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 58.164)), module, Mutes::MUTE_PARAM + 4, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 68.165)), module, Mutes::MUTE_PARAM + 5, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 78.164)), module, Mutes::MUTE_PARAM + 6, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 88.164)), module, Mutes::MUTE_PARAM + 7, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 98.165)), module, Mutes::MUTE_PARAM + 8, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 108.166)), module, Mutes::MUTE_PARAM + 9, 0.0f, 1.0f, 0.0f)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(4.214, 17.81)), PortWidget::INPUT, module, Mutes::IN_INPUT + 0)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(4.214, 27.809)), PortWidget::INPUT, module, Mutes::IN_INPUT + 1)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(4.214, 37.809)), PortWidget::INPUT, module, Mutes::IN_INPUT + 2)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(4.214, 47.81)), PortWidget::INPUT, module, Mutes::IN_INPUT + 3)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(4.214, 57.81)), PortWidget::INPUT, module, Mutes::IN_INPUT + 4)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(4.214, 67.809)), PortWidget::INPUT, module, Mutes::IN_INPUT + 5)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(4.214, 77.81)), PortWidget::INPUT, module, Mutes::IN_INPUT + 6)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(4.214, 87.81)), PortWidget::INPUT, module, Mutes::IN_INPUT + 7)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(4.214, 97.809)), PortWidget::INPUT, module, Mutes::IN_INPUT + 8)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(4.214, 107.809)), PortWidget::INPUT, module, Mutes::IN_INPUT + 9)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(28.214, 17.81)), PortWidget::OUTPUT, module, Mutes::OUT_OUTPUT + 0)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(28.214, 27.809)), PortWidget::OUTPUT, module, Mutes::OUT_OUTPUT + 1)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(28.214, 37.809)), PortWidget::OUTPUT, module, Mutes::OUT_OUTPUT + 2)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(28.214, 47.81)), PortWidget::OUTPUT, module, Mutes::OUT_OUTPUT + 3)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(28.214, 57.809)), PortWidget::OUTPUT, module, Mutes::OUT_OUTPUT + 4)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(28.214, 67.809)), PortWidget::OUTPUT, module, Mutes::OUT_OUTPUT + 5)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(28.214, 77.81)), PortWidget::OUTPUT, module, Mutes::OUT_OUTPUT + 6)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(28.214, 87.81)), PortWidget::OUTPUT, module, Mutes::OUT_OUTPUT + 7)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(28.214, 97.809)), PortWidget::OUTPUT, module, Mutes::OUT_OUTPUT + 8)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(28.214, 107.809)), PortWidget::OUTPUT, module, Mutes::OUT_OUTPUT + 9)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 18.165)), module, Mutes::MUTE_PARAM + 0)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 28.164)), module, Mutes::MUTE_PARAM + 1)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 38.164)), module, Mutes::MUTE_PARAM + 2)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 48.165)), module, Mutes::MUTE_PARAM + 3)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 58.164)), module, Mutes::MUTE_PARAM + 4)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 68.165)), module, Mutes::MUTE_PARAM + 5)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 78.164)), module, Mutes::MUTE_PARAM + 6)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 88.164)), module, Mutes::MUTE_PARAM + 7)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 98.165)), module, Mutes::MUTE_PARAM + 8)); | |||||
addParam(createParam<LEDBezel>(mm2px(Vec(16.57, 108.166)), module, Mutes::MUTE_PARAM + 9)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(4.214, 17.81)), module, Mutes::IN_INPUT + 0)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(4.214, 27.809)), module, Mutes::IN_INPUT + 1)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(4.214, 37.809)), module, Mutes::IN_INPUT + 2)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(4.214, 47.81)), module, Mutes::IN_INPUT + 3)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(4.214, 57.81)), module, Mutes::IN_INPUT + 4)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(4.214, 67.809)), module, Mutes::IN_INPUT + 5)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(4.214, 77.81)), module, Mutes::IN_INPUT + 6)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(4.214, 87.81)), module, Mutes::IN_INPUT + 7)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(4.214, 97.809)), module, Mutes::IN_INPUT + 8)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(4.214, 107.809)), module, Mutes::IN_INPUT + 9)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(28.214, 17.81)), module, Mutes::OUT_OUTPUT + 0)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(28.214, 27.809)), module, Mutes::OUT_OUTPUT + 1)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(28.214, 37.809)), module, Mutes::OUT_OUTPUT + 2)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(28.214, 47.81)), module, Mutes::OUT_OUTPUT + 3)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(28.214, 57.809)), module, Mutes::OUT_OUTPUT + 4)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(28.214, 67.809)), module, Mutes::OUT_OUTPUT + 5)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(28.214, 77.81)), module, Mutes::OUT_OUTPUT + 6)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(28.214, 87.81)), module, Mutes::OUT_OUTPUT + 7)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(28.214, 97.809)), module, Mutes::OUT_OUTPUT + 8)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(28.214, 107.809)), module, Mutes::OUT_OUTPUT + 9)); | |||||
addChild(createLight<MuteLight<GreenLight>>(mm2px(Vec(17.32, 18.915)), module, Mutes::MUTE_LIGHT + 0)); | addChild(createLight<MuteLight<GreenLight>>(mm2px(Vec(17.32, 18.915)), module, Mutes::MUTE_LIGHT + 0)); | ||||
addChild(createLight<MuteLight<GreenLight>>(mm2px(Vec(17.32, 28.916)), module, Mutes::MUTE_LIGHT + 1)); | addChild(createLight<MuteLight<GreenLight>>(mm2px(Vec(17.32, 28.916)), module, Mutes::MUTE_LIGHT + 1)); | ||||
@@ -38,16 +38,29 @@ struct SEQ3 : Module { | |||||
}; | }; | ||||
bool running = true; | bool running = true; | ||||
SchmittTrigger clockTrigger; | |||||
SchmittTrigger runningTrigger; | |||||
SchmittTrigger resetTrigger; | |||||
SchmittTrigger gateTriggers[8]; | |||||
dsp::SchmittTrigger clockTrigger; | |||||
dsp::SchmittTrigger runningTrigger; | |||||
dsp::SchmittTrigger resetTrigger; | |||||
dsp::SchmittTrigger gateTriggers[8]; | |||||
/** Phase of internal LFO */ | /** Phase of internal LFO */ | ||||
float phase = 0.f; | float phase = 0.f; | ||||
int index = 0; | int index = 0; | ||||
bool gates[8] = {}; | bool gates[8] = {}; | ||||
SEQ3() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||||
SEQ3() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
params[CLOCK_PARAM].config(-2.0f, 6.0f, 2.0f); | |||||
params[RUN_PARAM].config(0.0f, 1.0f, 0.0f); | |||||
params[RESET_PARAM].config(0.0f, 1.0f, 0.0f); | |||||
params[STEPS_PARAM].config(1.0f, 8.0f, 8.0f); | |||||
for (int i = 0; i < 8; i++) { | |||||
params[ROW1_PARAM + i].config(0.0f, 10.0f, 0.0f); | |||||
params[ROW2_PARAM + i].config(0.0f, 10.0f, 0.0f); | |||||
params[ROW3_PARAM + i].config(0.0f, 10.0f, 0.0f); | |||||
params[GATE_PARAM + i].config(0.0f, 1.0f, 0.0f); | |||||
} | |||||
onReset(); | onReset(); | ||||
} | } | ||||
@@ -59,7 +72,7 @@ struct SEQ3 : Module { | |||||
void onRandomize() override { | void onRandomize() override { | ||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
gates[i] = (randomUniform() > 0.5f); | |||||
gates[i] = (random::uniform() > 0.5f); | |||||
} | } | ||||
} | } | ||||
@@ -97,7 +110,7 @@ struct SEQ3 : Module { | |||||
} | } | ||||
void setIndex(int index) { | void setIndex(int index) { | ||||
int numSteps = (int) clamp(roundf(params[STEPS_PARAM].value + inputs[STEPS_INPUT].value), 1.0f, 8.0f); | |||||
int numSteps = (int) clamp(std::round(params[STEPS_PARAM].value + inputs[STEPS_INPUT].value), 1.0f, 8.0f); | |||||
phase = 0.f; | phase = 0.f; | ||||
this->index = index; | this->index = index; | ||||
if (this->index >= numSteps) | if (this->index >= numSteps) | ||||
@@ -121,8 +134,8 @@ struct SEQ3 : Module { | |||||
} | } | ||||
else { | else { | ||||
// Internal clock | // Internal clock | ||||
float clockTime = powf(2.0f, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value); | |||||
phase += clockTime * engineGetSampleTime(); | |||||
float clockTime = std::pow(2.0f, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value); | |||||
phase += clockTime * app()->engine->getSampleTime(); | |||||
if (phase >= 1.0f) { | if (phase >= 1.0f) { | ||||
setIndex(index + 1); | setIndex(index + 1); | ||||
} | } | ||||
@@ -161,41 +174,41 @@ struct SEQ3 : Module { | |||||
struct SEQ3Widget : ModuleWidget { | struct SEQ3Widget : ModuleWidget { | ||||
SEQ3Widget(SEQ3 *module) : ModuleWidget(module) { | SEQ3Widget(SEQ3 *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/SEQ3.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/SEQ3.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | addChild(createWidget<ScrewSilver>(Vec(15, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | addChild(createWidget<ScrewSilver>(Vec(15, 365))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365))); | ||||
addParam(createParam<RoundBlackKnob>(Vec(18, 56), module, SEQ3::CLOCK_PARAM, -2.0f, 6.0f, 2.0f)); | |||||
addParam(createParam<LEDButton>(Vec(60, 61-1), module, SEQ3::RUN_PARAM, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(18, 56), module, SEQ3::CLOCK_PARAM)); | |||||
addParam(createParam<LEDButton>(Vec(60, 61-1), module, SEQ3::RUN_PARAM)); | |||||
addChild(createLight<MediumLight<GreenLight>>(Vec(64.4f, 64.4f), module, SEQ3::RUNNING_LIGHT)); | addChild(createLight<MediumLight<GreenLight>>(Vec(64.4f, 64.4f), module, SEQ3::RUNNING_LIGHT)); | ||||
addParam(createParam<LEDButton>(Vec(99, 61-1), module, SEQ3::RESET_PARAM, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<LEDButton>(Vec(99, 61-1), module, SEQ3::RESET_PARAM)); | |||||
addChild(createLight<MediumLight<GreenLight>>(Vec(103.4f, 64.4f), module, SEQ3::RESET_LIGHT)); | addChild(createLight<MediumLight<GreenLight>>(Vec(103.4f, 64.4f), module, SEQ3::RESET_LIGHT)); | ||||
addParam(createParam<RoundBlackSnapKnob>(Vec(132, 56), module, SEQ3::STEPS_PARAM, 1.0f, 8.0f, 8.0f)); | |||||
addParam(createParam<RoundBlackSnapKnob>(Vec(132, 56), module, SEQ3::STEPS_PARAM)); | |||||
addChild(createLight<MediumLight<GreenLight>>(Vec(179.4f, 64.4f), module, SEQ3::GATES_LIGHT)); | addChild(createLight<MediumLight<GreenLight>>(Vec(179.4f, 64.4f), module, SEQ3::GATES_LIGHT)); | ||||
addChild(createLight<MediumLight<GreenLight>>(Vec(218.4f, 64.4f), module, SEQ3::ROW_LIGHTS)); | addChild(createLight<MediumLight<GreenLight>>(Vec(218.4f, 64.4f), module, SEQ3::ROW_LIGHTS)); | ||||
addChild(createLight<MediumLight<GreenLight>>(Vec(256.4f, 64.4f), module, SEQ3::ROW_LIGHTS + 1)); | addChild(createLight<MediumLight<GreenLight>>(Vec(256.4f, 64.4f), module, SEQ3::ROW_LIGHTS + 1)); | ||||
addChild(createLight<MediumLight<GreenLight>>(Vec(295.4f, 64.4f), module, SEQ3::ROW_LIGHTS + 2)); | addChild(createLight<MediumLight<GreenLight>>(Vec(295.4f, 64.4f), module, SEQ3::ROW_LIGHTS + 2)); | ||||
static const float portX[8] = {20, 58, 96, 135, 173, 212, 250, 289}; | static const float portX[8] = {20, 58, 96, 135, 173, 212, 250, 289}; | ||||
addInput(createPort<PJ301MPort>(Vec(portX[0]-1, 98), PortWidget::INPUT, module, SEQ3::CLOCK_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(portX[1]-1, 98), PortWidget::INPUT, module, SEQ3::EXT_CLOCK_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(portX[2]-1, 98), PortWidget::INPUT, module, SEQ3::RESET_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(portX[3]-1, 98), PortWidget::INPUT, module, SEQ3::STEPS_INPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(portX[4]-1, 98), PortWidget::OUTPUT, module, SEQ3::GATES_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(portX[5]-1, 98), PortWidget::OUTPUT, module, SEQ3::ROW1_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(portX[6]-1, 98), PortWidget::OUTPUT, module, SEQ3::ROW2_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(portX[7]-1, 98), PortWidget::OUTPUT, module, SEQ3::ROW3_OUTPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(portX[0]-1, 98), module, SEQ3::CLOCK_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(portX[1]-1, 98), module, SEQ3::EXT_CLOCK_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(portX[2]-1, 98), module, SEQ3::RESET_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(portX[3]-1, 98), module, SEQ3::STEPS_INPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(portX[4]-1, 98), module, SEQ3::GATES_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(portX[5]-1, 98), module, SEQ3::ROW1_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(portX[6]-1, 98), module, SEQ3::ROW2_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(portX[7]-1, 98), module, SEQ3::ROW3_OUTPUT)); | |||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
addParam(createParam<RoundBlackKnob>(Vec(portX[i]-2, 157), module, SEQ3::ROW1_PARAM + i, 0.0f, 10.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(portX[i]-2, 198), module, SEQ3::ROW2_PARAM + i, 0.0f, 10.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(portX[i]-2, 240), module, SEQ3::ROW3_PARAM + i, 0.0f, 10.0f, 0.0f)); | |||||
addParam(createParam<LEDButton>(Vec(portX[i]+2, 278-1), module, SEQ3::GATE_PARAM + i, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(portX[i]-2, 157), module, SEQ3::ROW1_PARAM + i)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(portX[i]-2, 198), module, SEQ3::ROW2_PARAM + i)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(portX[i]-2, 240), module, SEQ3::ROW3_PARAM + i)); | |||||
addParam(createParam<LEDButton>(Vec(portX[i]+2, 278-1), module, SEQ3::GATE_PARAM + i)); | |||||
addChild(createLight<MediumLight<GreenLight>>(Vec(portX[i]+6.4f, 281.4f), module, SEQ3::GATE_LIGHTS + i)); | addChild(createLight<MediumLight<GreenLight>>(Vec(portX[i]+6.4f, 281.4f), module, SEQ3::GATE_LIGHTS + i)); | ||||
addOutput(createPort<PJ301MPort>(Vec(portX[i]-1, 307), PortWidget::OUTPUT, module, SEQ3::GATE_OUTPUT + i)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(portX[i]-1, 307), module, SEQ3::GATE_OUTPUT + i)); | |||||
} | } | ||||
} | } | ||||
}; | }; | ||||
@@ -2,7 +2,8 @@ | |||||
#include "Fundamental.hpp" | #include "Fundamental.hpp" | ||||
#define BUFFER_SIZE 512 | |||||
static const int BUFFER_SIZE = 512; | |||||
struct Scope : Module { | struct Scope : Module { | ||||
enum ParamIds { | enum ParamIds { | ||||
@@ -38,14 +39,82 @@ struct Scope : Module { | |||||
int bufferIndex = 0; | int bufferIndex = 0; | ||||
float frameIndex = 0; | float frameIndex = 0; | ||||
SchmittTrigger sumTrigger; | |||||
SchmittTrigger extTrigger; | |||||
dsp::SchmittTrigger sumTrigger; | |||||
dsp::SchmittTrigger extTrigger; | |||||
bool lissajous = false; | bool lissajous = false; | ||||
bool external = false; | bool external = false; | ||||
SchmittTrigger resetTrigger; | |||||
dsp::SchmittTrigger resetTrigger; | |||||
Scope() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
params[X_SCALE_PARAM].config(-2.0f, 8.0f, 0.0f); | |||||
params[X_POS_PARAM].config(-10.0f, 10.0f, 0.0f); | |||||
params[Y_SCALE_PARAM].config(-2.0f, 8.0f, 0.0f); | |||||
params[Y_POS_PARAM].config(-10.0f, 10.0f, 0.0f); | |||||
params[TIME_PARAM].config(6.0f, 16.0f, 14.0f); | |||||
params[LISSAJOUS_PARAM].config(0.0f, 1.0f, 0.0f); | |||||
params[TRIG_PARAM].config(-10.0f, 10.0f, 0.0f); | |||||
params[EXTERNAL_PARAM].config(0.0f, 1.0f, 0.0f); | |||||
} | |||||
void step() override { | |||||
// Modes | |||||
if (sumTrigger.process(params[LISSAJOUS_PARAM].value)) { | |||||
lissajous = !lissajous; | |||||
} | |||||
lights[PLOT_LIGHT].value = lissajous ? 0.0f : 1.0f; | |||||
lights[LISSAJOUS_LIGHT].value = lissajous ? 1.0f : 0.0f; | |||||
if (extTrigger.process(params[EXTERNAL_PARAM].value)) { | |||||
external = !external; | |||||
} | |||||
lights[INTERNAL_LIGHT].value = external ? 0.0f : 1.0f; | |||||
lights[EXTERNAL_LIGHT].value = external ? 1.0f : 0.0f; | |||||
// Compute time | |||||
float deltaTime = std::pow(2.0f, -params[TIME_PARAM].value); | |||||
int frameCount = (int) std::ceil(deltaTime * app()->engine->getSampleRate()); | |||||
// Add frame to buffer | |||||
if (bufferIndex < BUFFER_SIZE) { | |||||
if (++frameIndex > frameCount) { | |||||
frameIndex = 0; | |||||
bufferX[bufferIndex] = inputs[X_INPUT].value; | |||||
bufferY[bufferIndex] = inputs[Y_INPUT].value; | |||||
bufferIndex++; | |||||
} | |||||
} | |||||
Scope() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||||
void step() override; | |||||
// Are we waiting on the next trigger? | |||||
if (bufferIndex >= BUFFER_SIZE) { | |||||
// Trigger immediately if external but nothing plugged in, or in Lissajous mode | |||||
if (lissajous || (external && !inputs[TRIG_INPUT].active)) { | |||||
bufferIndex = 0; | |||||
frameIndex = 0; | |||||
return; | |||||
} | |||||
// Reset the Schmitt trigger so we don't trigger immediately if the input is high | |||||
if (frameIndex == 0) { | |||||
resetTrigger.reset(); | |||||
} | |||||
frameIndex++; | |||||
// Must go below 0.1fV to trigger | |||||
float gate = external ? inputs[TRIG_INPUT].value : inputs[X_INPUT].value; | |||||
// Reset if triggered | |||||
float holdTime = 0.1f; | |||||
if (resetTrigger.process(rescale(gate, params[TRIG_PARAM].value - 0.1f, params[TRIG_PARAM].value, 0.f, 1.f)) || (frameIndex >= app()->engine->getSampleRate() * holdTime)) { | |||||
bufferIndex = 0; frameIndex = 0; return; | |||||
} | |||||
// Reset if we've waited too long | |||||
if (frameIndex >= app()->engine->getSampleRate() * holdTime) { | |||||
bufferIndex = 0; frameIndex = 0; return; | |||||
} | |||||
} | |||||
} | |||||
json_t *dataToJson() override { | json_t *dataToJson() override { | ||||
json_t *rootJ = json_object(); | json_t *rootJ = json_object(); | ||||
@@ -71,66 +140,6 @@ struct Scope : Module { | |||||
}; | }; | ||||
void Scope::step() { | |||||
// Modes | |||||
if (sumTrigger.process(params[LISSAJOUS_PARAM].value)) { | |||||
lissajous = !lissajous; | |||||
} | |||||
lights[PLOT_LIGHT].value = lissajous ? 0.0f : 1.0f; | |||||
lights[LISSAJOUS_LIGHT].value = lissajous ? 1.0f : 0.0f; | |||||
if (extTrigger.process(params[EXTERNAL_PARAM].value)) { | |||||
external = !external; | |||||
} | |||||
lights[INTERNAL_LIGHT].value = external ? 0.0f : 1.0f; | |||||
lights[EXTERNAL_LIGHT].value = external ? 1.0f : 0.0f; | |||||
// Compute time | |||||
float deltaTime = std::pow(2.0f, -params[TIME_PARAM].value); | |||||
int frameCount = (int) std::ceil(deltaTime * engineGetSampleRate()); | |||||
// Add frame to buffer | |||||
if (bufferIndex < BUFFER_SIZE) { | |||||
if (++frameIndex > frameCount) { | |||||
frameIndex = 0; | |||||
bufferX[bufferIndex] = inputs[X_INPUT].value; | |||||
bufferY[bufferIndex] = inputs[Y_INPUT].value; | |||||
bufferIndex++; | |||||
} | |||||
} | |||||
// Are we waiting on the next trigger? | |||||
if (bufferIndex >= BUFFER_SIZE) { | |||||
// Trigger immediately if external but nothing plugged in, or in Lissajous mode | |||||
if (lissajous || (external && !inputs[TRIG_INPUT].active)) { | |||||
bufferIndex = 0; | |||||
frameIndex = 0; | |||||
return; | |||||
} | |||||
// Reset the Schmitt trigger so we don't trigger immediately if the input is high | |||||
if (frameIndex == 0) { | |||||
resetTrigger.reset(); | |||||
} | |||||
frameIndex++; | |||||
// Must go below 0.1fV to trigger | |||||
float gate = external ? inputs[TRIG_INPUT].value : inputs[X_INPUT].value; | |||||
// Reset if triggered | |||||
float holdTime = 0.1f; | |||||
if (resetTrigger.process(rescale(gate, params[TRIG_PARAM].value - 0.1f, params[TRIG_PARAM].value, 0.f, 1.f)) || (frameIndex >= engineGetSampleRate() * holdTime)) { | |||||
bufferIndex = 0; frameIndex = 0; return; | |||||
} | |||||
// Reset if we've waited too long | |||||
if (frameIndex >= engineGetSampleRate() * holdTime) { | |||||
bufferIndex = 0; frameIndex = 0; return; | |||||
} | |||||
} | |||||
} | |||||
struct ScopeDisplay : TransparentWidget { | struct ScopeDisplay : TransparentWidget { | ||||
Scope *module; | Scope *module; | ||||
int frame = 0; | int frame = 0; | ||||
@@ -145,17 +154,17 @@ struct ScopeDisplay : TransparentWidget { | |||||
for (int i = 0; i < BUFFER_SIZE; i++) { | for (int i = 0; i < BUFFER_SIZE; i++) { | ||||
float v = values[i]; | float v = values[i]; | ||||
vrms += v*v; | vrms += v*v; | ||||
vmax = fmaxf(vmax, v); | |||||
vmin = fminf(vmin, v); | |||||
vmax = std::max(vmax, v); | |||||
vmin = std::min(vmin, v); | |||||
} | } | ||||
vrms = sqrtf(vrms / BUFFER_SIZE); | |||||
vrms = std::sqrt(vrms / BUFFER_SIZE); | |||||
vpp = vmax - vmin; | vpp = vmax - vmin; | ||||
} | } | ||||
}; | }; | ||||
Stats statsX, statsY; | Stats statsX, statsY; | ||||
ScopeDisplay() { | ScopeDisplay() { | ||||
font = Font::load(assetPlugin(plugin, "res/fonts/Sudo.ttf")); | |||||
font = Font::load(asset::plugin(plugin, "res/fonts/Sudo.ttf")); | |||||
} | } | ||||
void drawWaveform(NVGcontext *vg, float *valuesX, float *valuesY) { | void drawWaveform(NVGcontext *vg, float *valuesX, float *valuesY) { | ||||
@@ -306,7 +315,7 @@ struct ScopeWidget : ModuleWidget { | |||||
}; | }; | ||||
ScopeWidget::ScopeWidget(Scope *module) : ModuleWidget(module) { | ScopeWidget::ScopeWidget(Scope *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/Scope.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/Scope.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | addChild(createWidget<ScrewSilver>(Vec(15, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0))); | ||||
@@ -321,18 +330,18 @@ ScopeWidget::ScopeWidget(Scope *module) : ModuleWidget(module) { | |||||
addChild(display); | addChild(display); | ||||
} | } | ||||
addParam(createParam<RoundBlackSnapKnob>(Vec(15, 209), module, Scope::X_SCALE_PARAM, -2.0f, 8.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(15, 263), module, Scope::X_POS_PARAM, -10.0f, 10.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackSnapKnob>(Vec(61, 209), module, Scope::Y_SCALE_PARAM, -2.0f, 8.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(61, 263), module, Scope::Y_POS_PARAM, -10.0f, 10.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(107, 209), module, Scope::TIME_PARAM, 6.0f, 16.0f, 14.0f)); | |||||
addParam(createParam<CKD6>(Vec(106, 262), module, Scope::LISSAJOUS_PARAM, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(153, 209), module, Scope::TRIG_PARAM, -10.0f, 10.0f, 0.0f)); | |||||
addParam(createParam<CKD6>(Vec(152, 262), module, Scope::EXTERNAL_PARAM, 0.0f, 1.0f, 0.0f)); | |||||
addInput(createPort<PJ301MPort>(Vec(17, 319), PortWidget::INPUT, module, Scope::X_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(63, 319), PortWidget::INPUT, module, Scope::Y_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(154, 319), PortWidget::INPUT, module, Scope::TRIG_INPUT)); | |||||
addParam(createParam<RoundBlackSnapKnob>(Vec(15, 209), module, Scope::X_SCALE_PARAM)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(15, 263), module, Scope::X_POS_PARAM)); | |||||
addParam(createParam<RoundBlackSnapKnob>(Vec(61, 209), module, Scope::Y_SCALE_PARAM)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(61, 263), module, Scope::Y_POS_PARAM)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(107, 209), module, Scope::TIME_PARAM)); | |||||
addParam(createParam<CKD6>(Vec(106, 262), module, Scope::LISSAJOUS_PARAM)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(153, 209), module, Scope::TRIG_PARAM)); | |||||
addParam(createParam<CKD6>(Vec(152, 262), module, Scope::EXTERNAL_PARAM)); | |||||
addInput(createInput<PJ301MPort>(Vec(17, 319), module, Scope::X_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(63, 319), module, Scope::Y_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(154, 319), module, Scope::TRIG_INPUT)); | |||||
addChild(createLight<SmallLight<GreenLight>>(Vec(104, 251), module, Scope::PLOT_LIGHT)); | addChild(createLight<SmallLight<GreenLight>>(Vec(104, 251), module, Scope::PLOT_LIGHT)); | ||||
addChild(createLight<SmallLight<GreenLight>>(Vec(104, 296), module, Scope::LISSAJOUS_LIGHT)); | addChild(createLight<SmallLight<GreenLight>>(Vec(104, 296), module, Scope::LISSAJOUS_LIGHT)); | ||||
@@ -22,12 +22,15 @@ struct SequentialSwitch : Module { | |||||
NUM_LIGHTS | NUM_LIGHTS | ||||
}; | }; | ||||
SchmittTrigger clockTrigger; | |||||
SchmittTrigger resetTrigger; | |||||
dsp::SchmittTrigger clockTrigger; | |||||
dsp::SchmittTrigger resetTrigger; | |||||
int channel = 0; | int channel = 0; | ||||
SlewLimiter channelFilter[4]; | |||||
dsp::SlewLimiter channelFilter[4]; | |||||
SequentialSwitch() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
params[CHANNELS_PARAM].config(0.0, 2.0, 0.0); | |||||
SequentialSwitch() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
channelFilter[i].rise = 0.01f; | channelFilter[i].rise = 0.01f; | ||||
channelFilter[i].fall = 0.01f; | channelFilter[i].fall = 0.01f; | ||||
@@ -47,7 +50,7 @@ struct SequentialSwitch : Module { | |||||
// Filter channels | // Filter channels | ||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
channelFilter[i].process(channel == i ? 1.0f : 0.0f); | |||||
channelFilter[i].process(channel == i ? 1.f : 0.f); | |||||
} | } | ||||
// Set outputs | // Set outputs | ||||
@@ -58,7 +61,7 @@ struct SequentialSwitch : Module { | |||||
} | } | ||||
} | } | ||||
else { | else { | ||||
float out = 0.0f; | |||||
float out = 0.f; | |||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
out += channelFilter[i].out * inputs[IN_INPUT + i].value; | out += channelFilter[i].out * inputs[IN_INPUT + i].value; | ||||
} | } | ||||
@@ -79,21 +82,21 @@ struct SequentialSwitch1Widget : ModuleWidget { | |||||
SequentialSwitch1Widget::SequentialSwitch1Widget(SequentialSwitch<1> *module) : ModuleWidget(module) { | SequentialSwitch1Widget::SequentialSwitch1Widget(SequentialSwitch<1> *module) : ModuleWidget(module) { | ||||
typedef SequentialSwitch<1> TSequentialSwitch; | typedef SequentialSwitch<1> TSequentialSwitch; | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/SequentialSwitch1.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/SequentialSwitch1.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
addParam(createParam<CKSSThree>(mm2px(Vec(5.24619, 46.9153)), module, TSequentialSwitch::CHANNELS_PARAM, 0.0f, 2.0f, 0.0f)); | |||||
addParam(createParam<CKSSThree>(mm2px(Vec(5.24619, 46.9153)), module, TSequentialSwitch::CHANNELS_PARAM)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 17.694)), PortWidget::INPUT, module, TSequentialSwitch::CLOCK_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 32.1896)), PortWidget::INPUT, module, TSequentialSwitch::RESET_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51536, 62.8096)), PortWidget::INPUT, module, TSequentialSwitch::IN_INPUT + 0)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 17.694)), module, TSequentialSwitch::CLOCK_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 32.1896)), module, TSequentialSwitch::RESET_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51536, 62.8096)), module, TSequentialSwitch::IN_INPUT + 0)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(3.51536, 77.8095)), PortWidget::OUTPUT, module, TSequentialSwitch::OUT_OUTPUT + 0)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 87.8113)), PortWidget::OUTPUT, module, TSequentialSwitch::OUT_OUTPUT + 1)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 97.809)), PortWidget::OUTPUT, module, TSequentialSwitch::OUT_OUTPUT + 2)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 107.809)), PortWidget::OUTPUT, module, TSequentialSwitch::OUT_OUTPUT + 3)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51536, 77.8095)), module, TSequentialSwitch::OUT_OUTPUT + 0)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 87.8113)), module, TSequentialSwitch::OUT_OUTPUT + 1)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 97.809)), module, TSequentialSwitch::OUT_OUTPUT + 2)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 107.809)), module, TSequentialSwitch::OUT_OUTPUT + 3)); | |||||
addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.8203, 77.7158)), module, TSequentialSwitch::CHANNEL_LIGHT + 0)); | addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.8203, 77.7158)), module, TSequentialSwitch::CHANNEL_LIGHT + 0)); | ||||
addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.8203, 87.7163)), module, TSequentialSwitch::CHANNEL_LIGHT + 1)); | addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.8203, 87.7163)), module, TSequentialSwitch::CHANNEL_LIGHT + 1)); | ||||
@@ -111,21 +114,21 @@ struct SequentialSwitch2Widget : ModuleWidget { | |||||
SequentialSwitch2Widget::SequentialSwitch2Widget(SequentialSwitch<2> *module) : ModuleWidget(module) { | SequentialSwitch2Widget::SequentialSwitch2Widget(SequentialSwitch<2> *module) : ModuleWidget(module) { | ||||
typedef SequentialSwitch<2> TSequentialSwitch; | typedef SequentialSwitch<2> TSequentialSwitch; | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/SequentialSwitch2.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/SequentialSwitch2.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
addParam(createParam<CKSSThree>(mm2px(Vec(5.24619, 46.9153)), module, TSequentialSwitch::CHANNELS_PARAM, 0.0f, 2.0f, 0.0f)); | |||||
addParam(createParam<CKSSThree>(mm2px(Vec(5.24619, 46.9153)), module, TSequentialSwitch::CHANNELS_PARAM)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 17.694)), PortWidget::INPUT, module, TSequentialSwitch::CLOCK_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 32.191)), PortWidget::INPUT, module, TSequentialSwitch::RESET_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 62.811)), PortWidget::INPUT, module, TSequentialSwitch::IN_INPUT + 0)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 72.8114)), PortWidget::INPUT, module, TSequentialSwitch::IN_INPUT + 1)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 82.8091)), PortWidget::INPUT, module, TSequentialSwitch::IN_INPUT + 2)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 92.8109)), PortWidget::INPUT, module, TSequentialSwitch::IN_INPUT + 3)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 17.694)), module, TSequentialSwitch::CLOCK_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 32.191)), module, TSequentialSwitch::RESET_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 62.811)), module, TSequentialSwitch::IN_INPUT + 0)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 72.8114)), module, TSequentialSwitch::IN_INPUT + 1)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 82.8091)), module, TSequentialSwitch::IN_INPUT + 2)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 92.8109)), module, TSequentialSwitch::IN_INPUT + 3)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 107.622)), PortWidget::OUTPUT, module, TSequentialSwitch::OUT_OUTPUT + 0)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 107.622)), module, TSequentialSwitch::OUT_OUTPUT + 0)); | |||||
addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.7321, 62.6277)), module, TSequentialSwitch::CHANNEL_LIGHT + 0)); | addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.7321, 62.6277)), module, TSequentialSwitch::CHANNEL_LIGHT + 0)); | ||||
addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.7321, 72.6281)), module, TSequentialSwitch::CHANNEL_LIGHT + 1)); | addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.7321, 72.6281)), module, TSequentialSwitch::CHANNEL_LIGHT + 1)); | ||||
@@ -27,8 +27,50 @@ struct Unity : Module { | |||||
bool merge = false; | bool merge = false; | ||||
Unity() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||||
void step() override; | |||||
Unity() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
params[AVG1_PARAM].config(0.0, 1.0, 0.0); | |||||
params[AVG2_PARAM].config(0.0, 1.0, 0.0); | |||||
} | |||||
void step() override { | |||||
float mix[2] = {}; | |||||
int count[2] = {}; | |||||
for (int i = 0; i < 2; i++) { | |||||
// Inputs | |||||
for (int j = 0; j < 6; j++) { | |||||
mix[i] += inputs[IN1_INPUT + 6*i + j].value; | |||||
if (inputs[IN1_INPUT + 6*i + j].active) | |||||
count[i]++; | |||||
} | |||||
} | |||||
// Combine | |||||
if (merge) { | |||||
mix[0] += mix[1]; | |||||
mix[1] = mix[0]; | |||||
count[0] += count[1]; | |||||
count[1] = count[0]; | |||||
} | |||||
for (int i = 0; i < 2; i++) { | |||||
// Params | |||||
if ((int) params[AVG1_PARAM + i].value == 1 && count[i] > 0) | |||||
mix[i] /= count[i]; | |||||
// Outputs | |||||
outputs[MIX1_OUTPUT + 2*i].value = mix[i]; | |||||
outputs[INV1_OUTPUT + 2*i].value = -mix[i]; | |||||
// Lights | |||||
dsp::VUMeter vuMeter; | |||||
vuMeter.dBInterval = 6.0f; | |||||
vuMeter.setValue(mix[i] / 10.0f); | |||||
for (int j = 0; j < 5; j++) { | |||||
lights[VU1_LIGHT + 5*i + j].setBrightnessSmooth(vuMeter.getBrightness(j)); | |||||
} | |||||
} | |||||
} | |||||
void onReset() override { | void onReset() override { | ||||
merge = false; | merge = false; | ||||
@@ -49,44 +91,6 @@ struct Unity : Module { | |||||
} | } | ||||
}; | }; | ||||
void Unity::step() { | |||||
float mix[2] = {}; | |||||
int count[2] = {}; | |||||
for (int i = 0; i < 2; i++) { | |||||
// Inputs | |||||
for (int j = 0; j < 6; j++) { | |||||
mix[i] += inputs[IN1_INPUT + 6*i + j].value; | |||||
if (inputs[IN1_INPUT + 6*i + j].active) | |||||
count[i]++; | |||||
} | |||||
} | |||||
// Combine | |||||
if (merge) { | |||||
mix[0] += mix[1]; | |||||
mix[1] = mix[0]; | |||||
count[0] += count[1]; | |||||
count[1] = count[0]; | |||||
} | |||||
for (int i = 0; i < 2; i++) { | |||||
// Params | |||||
if ((int) params[AVG1_PARAM + i].value == 1 && count[i] > 0) | |||||
mix[i] /= count[i]; | |||||
// Outputs | |||||
outputs[MIX1_OUTPUT + 2*i].value = mix[i]; | |||||
outputs[INV1_OUTPUT + 2*i].value = -mix[i]; | |||||
// Lights | |||||
VUMeter vuMeter; | |||||
vuMeter.dBInterval = 6.0f; | |||||
vuMeter.setValue(mix[i] / 10.0f); | |||||
for (int j = 0; j < 5; j++) { | |||||
lights[VU1_LIGHT + 5*i + j].setBrightnessSmooth(vuMeter.getBrightness(j)); | |||||
} | |||||
} | |||||
} | |||||
struct UnityWidget : ModuleWidget { | struct UnityWidget : ModuleWidget { | ||||
@@ -95,33 +99,33 @@ struct UnityWidget : ModuleWidget { | |||||
}; | }; | ||||
UnityWidget::UnityWidget(Unity *module) : ModuleWidget(module) { | UnityWidget::UnityWidget(Unity *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/Unity.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/Unity.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | addChild(createWidget<ScrewSilver>(Vec(15, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | addChild(createWidget<ScrewSilver>(Vec(15, 365))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365))); | ||||
addParam(createParam<CKSS>(mm2px(Vec(12.867, 52.961)), module, Unity::AVG1_PARAM, 0.0f, 1.0f, 0.0f)); | |||||
addParam(createParam<CKSS>(mm2px(Vec(12.867, 107.006)), module, Unity::AVG2_PARAM, 0.0f, 1.0f, 0.0f)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(2.361, 17.144)), PortWidget::INPUT, module, Unity::IN1_INPUT + 0)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(19.907, 17.144)), PortWidget::INPUT, module, Unity::IN1_INPUT + 1)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(2.361, 28.145)), PortWidget::INPUT, module, Unity::IN1_INPUT + 2)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(19.907, 28.145)), PortWidget::INPUT, module, Unity::IN1_INPUT + 3)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(2.361, 39.145)), PortWidget::INPUT, module, Unity::IN1_INPUT + 4)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(19.907, 39.145)), PortWidget::INPUT, module, Unity::IN1_INPUT + 5)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(2.361, 71.145)), PortWidget::INPUT, module, Unity::IN2_INPUT + 0)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(19.907, 71.145)), PortWidget::INPUT, module, Unity::IN2_INPUT + 1)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(2.361, 82.145)), PortWidget::INPUT, module, Unity::IN2_INPUT + 2)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(19.907, 82.145)), PortWidget::INPUT, module, Unity::IN2_INPUT + 3)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(2.361, 93.144)), PortWidget::INPUT, module, Unity::IN2_INPUT + 4)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(19.907, 93.144)), PortWidget::INPUT, module, Unity::IN2_INPUT + 5)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(2.361, 54.15)), PortWidget::OUTPUT, module, Unity::MIX1_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(19.907, 54.15)), PortWidget::OUTPUT, module, Unity::INV1_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(2.361, 108.144)), PortWidget::OUTPUT, module, Unity::MIX2_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(19.907, 108.144)), PortWidget::OUTPUT, module, Unity::INV2_OUTPUT)); | |||||
addParam(createParam<CKSS>(mm2px(Vec(12.867, 52.961)), module, Unity::AVG1_PARAM)); | |||||
addParam(createParam<CKSS>(mm2px(Vec(12.867, 107.006)), module, Unity::AVG2_PARAM)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(2.361, 17.144)), module, Unity::IN1_INPUT + 0)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(19.907, 17.144)), module, Unity::IN1_INPUT + 1)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(2.361, 28.145)), module, Unity::IN1_INPUT + 2)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(19.907, 28.145)), module, Unity::IN1_INPUT + 3)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(2.361, 39.145)), module, Unity::IN1_INPUT + 4)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(19.907, 39.145)), module, Unity::IN1_INPUT + 5)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(2.361, 71.145)), module, Unity::IN2_INPUT + 0)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(19.907, 71.145)), module, Unity::IN2_INPUT + 1)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(2.361, 82.145)), module, Unity::IN2_INPUT + 2)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(19.907, 82.145)), module, Unity::IN2_INPUT + 3)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(2.361, 93.144)), module, Unity::IN2_INPUT + 4)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(19.907, 93.144)), module, Unity::IN2_INPUT + 5)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(2.361, 54.15)), module, Unity::MIX1_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(19.907, 54.15)), module, Unity::INV1_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(2.361, 108.144)), module, Unity::MIX2_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(19.907, 108.144)), module, Unity::INV2_OUTPUT)); | |||||
addChild(createLight<MediumLight<RedLight>>(mm2px(Vec(13.652, 19.663)), module, Unity::VU1_LIGHT + 0)); | addChild(createLight<MediumLight<RedLight>>(mm2px(Vec(13.652, 19.663)), module, Unity::VU1_LIGHT + 0)); | ||||
addChild(createLight<MediumLight<YellowLight>>(mm2px(Vec(13.652, 25.163)), module, Unity::VU1_LIGHT + 1)); | addChild(createLight<MediumLight<YellowLight>>(mm2px(Vec(13.652, 25.163)), module, Unity::VU1_LIGHT + 1)); | ||||
@@ -22,25 +22,28 @@ struct VCA : Module { | |||||
NUM_OUTPUTS | NUM_OUTPUTS | ||||
}; | }; | ||||
VCA() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} | |||||
void step() override; | |||||
}; | |||||
VCA() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | |||||
params[LEVEL1_PARAM].config(0.0, 1.0, 0.0); | |||||
params[LEVEL2_PARAM].config(0.0, 1.0, 0.0); | |||||
} | |||||
void stepChannel(InputIds in, ParamIds level, InputIds lin, InputIds exp, OutputIds out) { | |||||
float v = inputs[in].value * params[level].value; | |||||
if (inputs[lin].active) | |||||
v *= clamp(inputs[lin].value / 10.0f, 0.0f, 1.0f); | |||||
const float expBase = 50.0f; | |||||
if (inputs[exp].active) | |||||
v *= rescale(std::pow(expBase, clamp(inputs[exp].value / 10.0f, 0.0f, 1.0f)), 1.0f, expBase, 0.0f, 1.0f); | |||||
outputs[out].value = v; | |||||
} | |||||
static void stepChannel(Input &in, Param &level, Input &lin, Input &exp, Output &out) { | |||||
float v = in.value * level.value; | |||||
if (lin.active) | |||||
v *= clamp(lin.value / 10.0f, 0.0f, 1.0f); | |||||
const float expBase = 50.0f; | |||||
if (exp.active) | |||||
v *= rescale(powf(expBase, clamp(exp.value / 10.0f, 0.0f, 1.0f)), 1.0f, expBase, 0.0f, 1.0f); | |||||
out.value = v; | |||||
} | |||||
void step() override { | |||||
stepChannel(IN1_INPUT, LEVEL1_PARAM, LIN1_INPUT, EXP1_INPUT, OUT1_OUTPUT); | |||||
stepChannel(IN2_INPUT, LEVEL2_PARAM, LIN2_INPUT, EXP2_INPUT, OUT2_OUTPUT); | |||||
} | |||||
}; | |||||
void VCA::step() { | |||||
stepChannel(inputs[IN1_INPUT], params[LEVEL1_PARAM], inputs[LIN1_INPUT], inputs[EXP1_INPUT], outputs[OUT1_OUTPUT]); | |||||
stepChannel(inputs[IN2_INPUT], params[LEVEL2_PARAM], inputs[LIN2_INPUT], inputs[EXP2_INPUT], outputs[OUT2_OUTPUT]); | |||||
} | |||||
struct VCAWidget : ModuleWidget { | struct VCAWidget : ModuleWidget { | ||||
@@ -48,25 +51,25 @@ struct VCAWidget : ModuleWidget { | |||||
}; | }; | ||||
VCAWidget::VCAWidget(VCA *module) : ModuleWidget(module) { | VCAWidget::VCAWidget(VCA *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/VCA.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/VCA.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
addParam(createParam<RoundLargeBlackKnob>(mm2px(Vec(6.35, 19.11753)), module, VCA::LEVEL1_PARAM, 0.0, 1.0, 0.0)); | |||||
addParam(createParam<RoundLargeBlackKnob>(mm2px(Vec(6.35, 74.80544)), module, VCA::LEVEL2_PARAM, 0.0, 1.0, 0.0)); | |||||
addParam(createParam<RoundLargeBlackKnob>(mm2px(Vec(6.35, 19.11753)), module, VCA::LEVEL1_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(mm2px(Vec(6.35, 74.80544)), module, VCA::LEVEL2_PARAM)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(2.5907, 38.19371)), PortWidget::INPUT, module, VCA::EXP1_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(14.59752, 38.19371)), PortWidget::INPUT, module, VCA::LIN1_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(2.5907, 52.80642)), PortWidget::INPUT, module, VCA::IN1_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(2.5907, 93.53435)), PortWidget::INPUT, module, VCA::EXP2_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(14.59752, 93.53435)), PortWidget::INPUT, module, VCA::LIN2_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(2.5907, 108.14706)), PortWidget::INPUT, module, VCA::IN2_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(2.5907, 38.19371)), module, VCA::EXP1_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(14.59752, 38.19371)), module, VCA::LIN1_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(2.5907, 52.80642)), module, VCA::IN1_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(2.5907, 93.53435)), module, VCA::EXP2_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(14.59752, 93.53435)), module, VCA::LIN2_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(2.5907, 108.14706)), module, VCA::IN2_INPUT)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(14.59752, 52.80642)), PortWidget::OUTPUT, module, VCA::OUT1_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(14.59752, 108.14706)), PortWidget::OUTPUT, module, VCA::OUT2_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(14.59752, 52.80642)), module, VCA::OUT1_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(14.59752, 108.14706)), module, VCA::OUT2_OUTPUT)); | |||||
} | } | ||||
@@ -91,12 +94,16 @@ struct VCA_1 : Module { | |||||
float lastCv = 0.f; | float lastCv = 0.f; | ||||
VCA_1() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||||
VCA_1() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
params[LEVEL_PARAM].config(0.0, 1.0, 1.0); | |||||
params[EXP_PARAM].config(0.0, 1.0, 1.0); | |||||
} | |||||
void step() override { | void step() override { | ||||
float cv = inputs[CV_INPUT].normalize(10.f) / 10.f; | float cv = inputs[CV_INPUT].normalize(10.f) / 10.f; | ||||
if ((int) params[EXP_PARAM].value == 0) | if ((int) params[EXP_PARAM].value == 0) | ||||
cv = powf(cv, 4.f); | |||||
cv = std::pow(cv, 4.f); | |||||
lastCv = cv; | lastCv = cv; | ||||
outputs[OUT_OUTPUT].value = inputs[IN_INPUT].value * params[LEVEL_PARAM].value * cv; | outputs[OUT_OUTPUT].value = inputs[IN_INPUT].value * params[LEVEL_PARAM].value * cv; | ||||
} | } | ||||
@@ -133,11 +140,11 @@ struct VCA_1VUKnob : Knob { | |||||
nvgRect(vg, r.pos.x, r.pos.y + r.size.y / segs * i + 0.5, | nvgRect(vg, r.pos.x, r.pos.y + r.size.y / segs * i + 0.5, | ||||
r.size.x, r.size.y / segs - 1.0); | r.size.x, r.size.y / segs - 1.0); | ||||
if (segValue > 0.f) { | if (segValue > 0.f) { | ||||
nvgFillColor(vg, colorAlpha(nvgRGBf(0.33, 0.33, 0.33), segValue)); | |||||
nvgFillColor(vg, color::alpha(nvgRGBf(0.33, 0.33, 0.33), segValue)); | |||||
nvgFill(vg); | nvgFill(vg); | ||||
} | } | ||||
if (segAmplitude > 0.f) { | if (segAmplitude > 0.f) { | ||||
nvgFillColor(vg, colorAlpha(COLOR_GREEN, segAmplitude)); | |||||
nvgFillColor(vg, color::alpha(color::GREEN, segAmplitude)); | |||||
nvgFill(vg); | nvgFill(vg); | ||||
} | } | ||||
} | } | ||||
@@ -147,22 +154,22 @@ struct VCA_1VUKnob : Knob { | |||||
struct VCA_1Widget : ModuleWidget { | struct VCA_1Widget : ModuleWidget { | ||||
VCA_1Widget(VCA_1 *module) : ModuleWidget(module) { | VCA_1Widget(VCA_1 *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/VCA-1.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/VCA-1.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
VCA_1VUKnob *levelParam = createParam<VCA_1VUKnob>(mm2px(Vec(2.62103, 12.31692)), module, VCA_1::LEVEL_PARAM, 0.0, 1.0, 1.0); | |||||
VCA_1VUKnob *levelParam = createParam<VCA_1VUKnob>(mm2px(Vec(2.62103, 12.31692)), module, VCA_1::LEVEL_PARAM); | |||||
levelParam->module = module; | levelParam->module = module; | ||||
addParam(levelParam); | addParam(levelParam); | ||||
addParam(createParam<CKSS>(mm2px(Vec(5.24619, 79.9593)), module, VCA_1::EXP_PARAM, 0.0, 1.0, 1.0)); | |||||
addParam(createParam<CKSS>(mm2px(Vec(5.24619, 79.9593)), module, VCA_1::EXP_PARAM)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51261, 60.4008)), PortWidget::INPUT, module, VCA_1::CV_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 97.74977)), PortWidget::INPUT, module, VCA_1::IN_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51261, 60.4008)), module, VCA_1::CV_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 97.74977)), module, VCA_1::IN_INPUT)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(3.51398, 108.64454)), PortWidget::OUTPUT, module, VCA_1::OUT_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 108.64454)), module, VCA_1::OUT_OUTPUT)); | |||||
} | } | ||||
}; | }; | ||||
@@ -1,8 +1,8 @@ | |||||
#include "Fundamental.hpp" | #include "Fundamental.hpp" | ||||
inline float clip(float x) { | |||||
return tanhf(x); | |||||
static float clip(float x) { | |||||
return std::tanh(x); | |||||
} | } | ||||
struct LadderFilter { | struct LadderFilter { | ||||
@@ -78,7 +78,14 @@ struct VCF : Module { | |||||
// Decimator<UPSAMPLE, 8> lowpassDecimator; | // Decimator<UPSAMPLE, 8> lowpassDecimator; | ||||
// Decimator<UPSAMPLE, 8> highpassDecimator; | // Decimator<UPSAMPLE, 8> highpassDecimator; | ||||
VCF() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} | |||||
VCF() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | |||||
params[FREQ_PARAM].config(0.f, 1.f, 0.5f); | |||||
params[FINE_PARAM].config(0.f, 1.f, 0.5f); | |||||
params[RES_PARAM].config(0.f, 1.f, 0.f); | |||||
params[FREQ_CV_PARAM].config(-1.f, 1.f, 0.f); | |||||
params[DRIVE_PARAM].config(0.f, 1.f, 0.f); | |||||
} | |||||
void onReset() override { | void onReset() override { | ||||
filter.reset(); | filter.reset(); | ||||
@@ -97,7 +104,7 @@ struct VCF : Module { | |||||
input *= gain; | input *= gain; | ||||
// Add -60dB noise to bootstrap self-oscillation | // Add -60dB noise to bootstrap self-oscillation | ||||
input += 1e-6f * (2.f * randomUniform() - 1.f); | |||||
input += 1e-6f * (2.f * random::uniform() - 1.f); | |||||
// Set resonance | // Set resonance | ||||
float res = clamp(params[RES_PARAM].value + inputs[RES_INPUT].value / 10.f, 0.f, 1.f); | float res = clamp(params[RES_PARAM].value + inputs[RES_INPUT].value / 10.f, 0.f, 1.f); | ||||
@@ -106,16 +113,16 @@ struct VCF : Module { | |||||
// Set cutoff frequency | // Set cutoff frequency | ||||
float pitch = 0.f; | float pitch = 0.f; | ||||
if (inputs[FREQ_INPUT].active) | if (inputs[FREQ_INPUT].active) | ||||
pitch += inputs[FREQ_INPUT].value * quadraticBipolar(params[FREQ_CV_PARAM].value); | |||||
pitch += inputs[FREQ_INPUT].value * dsp::quadraticBipolar(params[FREQ_CV_PARAM].value); | |||||
pitch += params[FREQ_PARAM].value * 10.f - 5.f; | pitch += params[FREQ_PARAM].value * 10.f - 5.f; | ||||
pitch += quadraticBipolar(params[FINE_PARAM].value * 2.f - 1.f) * 7.f / 12.f; | |||||
pitch += dsp::quadraticBipolar(params[FINE_PARAM].value * 2.f - 1.f) * 7.f / 12.f; | |||||
float cutoff = 261.626f * powf(2.f, pitch); | float cutoff = 261.626f * powf(2.f, pitch); | ||||
cutoff = clamp(cutoff, 1.f, 8000.f); | cutoff = clamp(cutoff, 1.f, 8000.f); | ||||
filter.setCutoff(cutoff); | filter.setCutoff(cutoff); | ||||
/* | /* | ||||
// Process sample | // Process sample | ||||
float dt = engineGetSampleTime() / UPSAMPLE; | |||||
float dt = app()->engine->getSampleTime() / UPSAMPLE; | |||||
float inputBuf[UPSAMPLE]; | float inputBuf[UPSAMPLE]; | ||||
float lowpassBuf[UPSAMPLE]; | float lowpassBuf[UPSAMPLE]; | ||||
float highpassBuf[UPSAMPLE]; | float highpassBuf[UPSAMPLE]; | ||||
@@ -135,7 +142,7 @@ struct VCF : Module { | |||||
outputs[HPF_OUTPUT].value = 5.f * highpassDecimator.process(highpassBuf); | outputs[HPF_OUTPUT].value = 5.f * highpassDecimator.process(highpassBuf); | ||||
} | } | ||||
*/ | */ | ||||
filter.process(input, engineGetSampleTime()); | |||||
filter.process(input, app()->engine->getSampleTime()); | |||||
outputs[LPF_OUTPUT].value = 5.f * filter.lowpass; | outputs[LPF_OUTPUT].value = 5.f * filter.lowpass; | ||||
outputs[HPF_OUTPUT].value = 5.f * filter.highpass; | outputs[HPF_OUTPUT].value = 5.f * filter.highpass; | ||||
} | } | ||||
@@ -144,29 +151,28 @@ struct VCF : Module { | |||||
struct VCFWidget : ModuleWidget { | struct VCFWidget : ModuleWidget { | ||||
VCFWidget(VCF *module) : ModuleWidget(module) { | VCFWidget(VCF *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/VCF.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/VCF.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | addChild(createWidget<ScrewSilver>(Vec(15, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | addChild(createWidget<ScrewSilver>(Vec(15, 365))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365))); | ||||
addParam(createParam<RoundHugeBlackKnob>(Vec(33, 61), module, VCF::FREQ_PARAM, 0.f, 1.f, 0.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(12, 143), module, VCF::FINE_PARAM, 0.f, 1.f, 0.5f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(71, 143), module, VCF::RES_PARAM, 0.f, 1.f, 0.f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(12, 208), module, VCF::FREQ_CV_PARAM, -1.f, 1.f, 0.f)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(71, 208), module, VCF::DRIVE_PARAM, 0.f, 1.f, 0.f)); | |||||
addParam(createParam<RoundHugeBlackKnob>(Vec(33, 61), module, VCF::FREQ_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(12, 143), module, VCF::FINE_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(71, 143), module, VCF::RES_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(12, 208), module, VCF::FREQ_CV_PARAM)); | |||||
addParam(createParam<RoundLargeBlackKnob>(Vec(71, 208), module, VCF::DRIVE_PARAM)); | |||||
addInput(createPort<PJ301MPort>(Vec(10, 276), PortWidget::INPUT, module, VCF::FREQ_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(48, 276), PortWidget::INPUT, module, VCF::RES_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(85, 276), PortWidget::INPUT, module, VCF::DRIVE_INPUT)); | |||||
addInput(createPort<PJ301MPort>(Vec(10, 320), PortWidget::INPUT, module, VCF::IN_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(10, 276), module, VCF::FREQ_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(48, 276), module, VCF::RES_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(85, 276), module, VCF::DRIVE_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(10, 320), module, VCF::IN_INPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(48, 320), PortWidget::OUTPUT, module, VCF::LPF_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(Vec(85, 320), PortWidget::OUTPUT, module, VCF::HPF_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(48, 320), module, VCF::LPF_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(Vec(85, 320), module, VCF::HPF_OUTPUT)); | |||||
} | } | ||||
}; | }; | ||||
Model *modelVCF = createModel<VCF, VCFWidget>("VCF"); | Model *modelVCF = createModel<VCF, VCFWidget>("VCF"); |
@@ -19,13 +19,20 @@ struct VCMixer : Module { | |||||
NUM_OUTPUTS | NUM_OUTPUTS | ||||
}; | }; | ||||
VCMixer() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} | |||||
VCMixer() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | |||||
params[MIX_LVL_PARAM].config(0.0, 2.0, 1.0); | |||||
params[LVL_PARAM + 0].config(0.0, 1.0, 1.0); | |||||
params[LVL_PARAM + 1].config(0.0, 1.0, 1.0); | |||||
params[LVL_PARAM + 2].config(0.0, 1.0, 1.0); | |||||
params[LVL_PARAM + 3].config(0.0, 1.0, 1.0); | |||||
} | |||||
void step() override { | void step() override { | ||||
float mix = 0.f; | float mix = 0.f; | ||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
float ch = inputs[CH_INPUT + i].value; | float ch = inputs[CH_INPUT + i].value; | ||||
ch *= powf(params[LVL_PARAM + i].value, 2.f); | |||||
ch *= std::pow(params[LVL_PARAM + i].value, 2.f); | |||||
if (inputs[CV_INPUT + i].active) | if (inputs[CV_INPUT + i].active) | ||||
ch *= clamp(inputs[CV_INPUT + i].value / 10.f, 0.f, 1.f); | ch *= clamp(inputs[CV_INPUT + i].value / 10.f, 0.f, 1.f); | ||||
outputs[CH_OUTPUT + i].value = ch; | outputs[CH_OUTPUT + i].value = ch; | ||||
@@ -41,35 +48,35 @@ struct VCMixer : Module { | |||||
struct VCMixerWidget : ModuleWidget { | struct VCMixerWidget : ModuleWidget { | ||||
VCMixerWidget(VCMixer *module) : ModuleWidget(module) { | VCMixerWidget(VCMixer *module) : ModuleWidget(module) { | ||||
setPanel(SVG::load(assetPlugin(plugin, "res/VCMixer.svg"))); | |||||
setPanel(SVG::load(asset::plugin(plugin, "res/VCMixer.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | ||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
addParam(createParam<RoundLargeBlackKnob>(mm2px(Vec(19.049999, 21.161154)), module, VCMixer::MIX_LVL_PARAM, 0.0, 2.0, 1.0)); | |||||
addParam(createParam<LEDSliderGreen>(mm2px(Vec(5.8993969, 44.33149).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 0, 0.0, 1.0, 1.0)); | |||||
addParam(createParam<LEDSliderGreen>(mm2px(Vec(17.899343, 44.331486).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 1, 0.0, 1.0, 1.0)); | |||||
addParam(createParam<LEDSliderGreen>(mm2px(Vec(29.899292, 44.331486).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 2, 0.0, 1.0, 1.0)); | |||||
addParam(createParam<LEDSliderGreen>(mm2px(Vec(41.90065, 44.331486).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 3, 0.0, 1.0, 1.0)); | |||||
addParam(createParam<RoundLargeBlackKnob>(mm2px(Vec(19.049999, 21.161154)), module, VCMixer::MIX_LVL_PARAM)); | |||||
addParam(createParam<LEDSliderGreen>(mm2px(Vec(5.8993969, 44.33149).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 0)); | |||||
addParam(createParam<LEDSliderGreen>(mm2px(Vec(17.899343, 44.331486).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 1)); | |||||
addParam(createParam<LEDSliderGreen>(mm2px(Vec(29.899292, 44.331486).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 2)); | |||||
addParam(createParam<LEDSliderGreen>(mm2px(Vec(41.90065, 44.331486).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 3)); | |||||
// Use old interleaved order for backward compatibility with <0.6 | // Use old interleaved order for backward compatibility with <0.6 | ||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.2935331, 23.404598)), PortWidget::INPUT, module, VCMixer::MIX_CV_INPUT)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.2935331, 78.531639)), PortWidget::INPUT, module, VCMixer::CH_INPUT + 0)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(3.2935331, 93.531586)), PortWidget::INPUT, module, VCMixer::CV_INPUT + 0)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(15.29348, 78.531639)), PortWidget::INPUT, module, VCMixer::CH_INPUT + 1)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(15.29348, 93.531586)), PortWidget::INPUT, module, VCMixer::CV_INPUT + 1)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(27.293465, 78.531639)), PortWidget::INPUT, module, VCMixer::CH_INPUT + 2)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(27.293465, 93.531586)), PortWidget::INPUT, module, VCMixer::CV_INPUT + 2)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(39.293411, 78.531639)), PortWidget::INPUT, module, VCMixer::CH_INPUT + 3)); | |||||
addInput(createPort<PJ301MPort>(mm2px(Vec(39.293411, 93.531586)), PortWidget::INPUT, module, VCMixer::CV_INPUT + 3)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.2935331, 23.404598)), module, VCMixer::MIX_CV_INPUT)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.2935331, 78.531639)), module, VCMixer::CH_INPUT + 0)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(3.2935331, 93.531586)), module, VCMixer::CV_INPUT + 0)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(15.29348, 78.531639)), module, VCMixer::CH_INPUT + 1)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(15.29348, 93.531586)), module, VCMixer::CV_INPUT + 1)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(27.293465, 78.531639)), module, VCMixer::CH_INPUT + 2)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(27.293465, 93.531586)), module, VCMixer::CV_INPUT + 2)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(39.293411, 78.531639)), module, VCMixer::CH_INPUT + 3)); | |||||
addInput(createInput<PJ301MPort>(mm2px(Vec(39.293411, 93.531586)), module, VCMixer::CV_INPUT + 3)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(39.293411, 23.4046)), PortWidget::OUTPUT, module, VCMixer::MIX_OUTPUT)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(3.2935331, 108.53153)), PortWidget::OUTPUT, module, VCMixer::CH_OUTPUT + 0)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(15.29348, 108.53153)), PortWidget::OUTPUT, module, VCMixer::CH_OUTPUT + 1)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(27.293465, 108.53153)), PortWidget::OUTPUT, module, VCMixer::CH_OUTPUT + 2)); | |||||
addOutput(createPort<PJ301MPort>(mm2px(Vec(39.293411, 108.53153)), PortWidget::OUTPUT, module, VCMixer::CH_OUTPUT + 3)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(39.293411, 23.4046)), module, VCMixer::MIX_OUTPUT)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.2935331, 108.53153)), module, VCMixer::CH_OUTPUT + 0)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.29348, 108.53153)), module, VCMixer::CH_OUTPUT + 1)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.293465, 108.53153)), module, VCMixer::CH_OUTPUT + 2)); | |||||
addOutput(createOutput<PJ301MPort>(mm2px(Vec(39.293411, 108.53153)), module, VCMixer::CH_OUTPUT + 3)); | |||||
} | } | ||||
}; | }; | ||||
@@ -17,11 +17,11 @@ struct VoltageControlledOscillator { | |||||
bool syncEnabled = false; | bool syncEnabled = false; | ||||
bool syncDirection = false; | bool syncDirection = false; | ||||
Decimator<OVERSAMPLE, QUALITY> sinDecimator; | |||||
Decimator<OVERSAMPLE, QUALITY> triDecimator; | |||||
Decimator<OVERSAMPLE, QUALITY> sawDecimator; | |||||
Decimator<OVERSAMPLE, QUALITY> sqrDecimator; | |||||
RCFilter sqrFilter; | |||||
dsp::Decimator<OVERSAMPLE, QUALITY> sinDecimator; | |||||
dsp::Decimator<OVERSAMPLE, QUALITY> triDecimator; | |||||
dsp::Decimator<OVERSAMPLE, QUALITY> sawDecimator; | |||||
dsp::Decimator<OVERSAMPLE, QUALITY> sqrDecimator; | |||||
dsp::RCFilter sqrFilter; | |||||
// For analog detuning effect | // For analog detuning effect | ||||
float pitchSlew = 0.0f; | float pitchSlew = 0.0f; | ||||
@@ -42,11 +42,11 @@ struct VoltageControlledOscillator { | |||||
} | } | ||||
else { | else { | ||||
// Quantize coarse knob if digital mode | // Quantize coarse knob if digital mode | ||||
pitch = roundf(pitch); | |||||
pitch = std::round(pitch); | |||||
} | } | ||||
pitch += pitchCv; | pitch += pitchCv; | ||||
// Note C4 | // Note C4 | ||||
freq = dsp::FREQ_C4 * powf(2.0f, pitch / 12.0f); | |||||
freq = dsp::FREQ_C4 * std::pow(2.0f, pitch / 12.0f); | |||||
} | } | ||||
void setPulseWidth(float pulseWidth) { | void setPulseWidth(float pulseWidth) { | ||||
const float pwMin = 0.01f; | const float pwMin = 0.01f; | ||||
@@ -101,9 +101,9 @@ struct VoltageControlledOscillator { | |||||
if (analog) { | if (analog) { | ||||
// Quadratic approximation of sine, slightly richer harmonics | // Quadratic approximation of sine, slightly richer harmonics | ||||
if (phase < 0.5f) | if (phase < 0.5f) | ||||
sinBuffer[i] = 1.f - 16.f * powf(phase - 0.25f, 2); | |||||
sinBuffer[i] = 1.f - 16.f * std::pow(phase - 0.25f, 2); | |||||
else | else | ||||
sinBuffer[i] = -1.f + 16.f * powf(phase - 0.75f, 2); | |||||
sinBuffer[i] = -1.f + 16.f * std::pow(phase - 0.75f, 2); | |||||
sinBuffer[i] *= 1.08f; | sinBuffer[i] *= 1.08f; | ||||
} | } | ||||
else { | else { | ||||
@@ -211,10 +211,10 @@ void VCO::step() { | |||||
oscillator.analog = params[MODE_PARAM].value > 0.0f; | oscillator.analog = params[MODE_PARAM].value > 0.0f; | ||||
oscillator.soft = params[SYNC_PARAM].value <= 0.0f; | oscillator.soft = params[SYNC_PARAM].value <= 0.0f; | ||||
float pitchFine = 3.0f * quadraticBipolar(params[FINE_PARAM].value); | |||||
float pitchFine = 3.0f * dsp::quadraticBipolar(params[FINE_PARAM].value); | |||||
float pitchCv = 12.0f * inputs[PITCH_INPUT].value; | float pitchCv = 12.0f * inputs[PITCH_INPUT].value; | ||||
if (inputs[FM_INPUT].active) { | if (inputs[FM_INPUT].active) { | ||||
pitchCv += quadraticBipolar(params[FM_PARAM].value) * 12.0f * inputs[FM_INPUT].value; | |||||
pitchCv += dsp::quadraticBipolar(params[FM_PARAM].value) * 12.0f * inputs[FM_INPUT].value; | |||||
} | } | ||||
oscillator.setPitch(params[FREQ_PARAM].value, pitchFine + pitchCv); | oscillator.setPitch(params[FREQ_PARAM].value, pitchFine + pitchCv); | ||||
oscillator.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.0f); | oscillator.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.0f); | ||||
@@ -318,7 +318,7 @@ void VCO2::step() { | |||||
oscillator.analog = params[MODE_PARAM].value > 0.0f; | oscillator.analog = params[MODE_PARAM].value > 0.0f; | ||||
oscillator.soft = params[SYNC_PARAM].value <= 0.0f; | oscillator.soft = params[SYNC_PARAM].value <= 0.0f; | ||||
float pitchCv = params[FREQ_PARAM].value + quadraticBipolar(params[FM_PARAM].value) * 12.0f * inputs[FM_INPUT].value; | |||||
float pitchCv = params[FREQ_PARAM].value + dsp::quadraticBipolar(params[FM_PARAM].value) * 12.0f * inputs[FM_INPUT].value; | |||||
oscillator.setPitch(0.0f, pitchCv); | oscillator.setPitch(0.0f, pitchCv); | ||||
oscillator.syncEnabled = inputs[SYNC_INPUT].active; | oscillator.syncEnabled = inputs[SYNC_INPUT].active; | ||||