| @@ -3,32 +3,45 @@ | |||
| struct _8vert : Module { | |||
| enum ParamIds { | |||
| NUM_PARAMS = 8 | |||
| ENUMS(GAIN_PARAMS, 8), | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| NUM_INPUTS = 8 | |||
| ENUMS(IN_INPUTS, 8), | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| NUM_OUTPUTS = 8 | |||
| ENUMS(OUT_OUTPUTS, 8), | |||
| NUM_OUTPUTS | |||
| }; | |||
| 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 { | |||
| @@ -36,48 +49,48 @@ struct _8vertWidget : ModuleWidget { | |||
| }; | |||
| _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(box.size.x - 30, 0))); | |||
| addChild(createWidget<ScrewSilver>(Vec(15, 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; | |||
| 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 { | |||
| 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 { | |||
| // 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 { | |||
| 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 { | |||
| @@ -106,26 +110,26 @@ struct ADSRWidget : ModuleWidget { | |||
| }; | |||
| 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(box.size.x-30, 0))); | |||
| addChild(createWidget<ScrewSilver>(Vec(15, 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, 109), module, ADSR::DECAY_LIGHT)); | |||
| @@ -25,14 +25,20 @@ struct Delay : Module { | |||
| 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; | |||
| 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); | |||
| assert(src); | |||
| } | |||
| @@ -41,96 +47,91 @@ struct Delay : Module { | |||
| 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 { | |||
| 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"); | |||
| @@ -5,8 +5,6 @@ Plugin *plugin; | |||
| void init(rack::Plugin *p) { | |||
| plugin = p; | |||
| p->slug = TOSTRING(SLUG); | |||
| p->version = TOSTRING(VERSION); | |||
| p->addModel(modelVCO); | |||
| p->addModel(modelVCO2); | |||
| @@ -1,4 +1,5 @@ | |||
| #include "rack0.hpp" | |||
| #include "rack.hpp" | |||
| #include "componentlibrary.hpp" | |||
| using namespace rack; | |||
| @@ -2,63 +2,63 @@ | |||
| struct LowFrequencyOscillator { | |||
| float phase = 0.0f; | |||
| float phase = 0.f; | |||
| float pw = 0.5f; | |||
| float freq = 1.0f; | |||
| float freq = 1.f; | |||
| bool offset = false; | |||
| bool invert = false; | |||
| SchmittTrigger resetTrigger; | |||
| dsp::SchmittTrigger resetTrigger; | |||
| LowFrequencyOscillator() {} | |||
| 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_) { | |||
| const float pwMin = 0.01f; | |||
| pw = clamp(pw_, pwMin, 1.0f - pwMin); | |||
| pw = clamp(pw_, pwMin, 1.f - pwMin); | |||
| } | |||
| void setReset(float reset) { | |||
| if (resetTrigger.process(reset / 0.01f)) { | |||
| phase = 0.0f; | |||
| phase = 0.f; | |||
| } | |||
| } | |||
| void step(float dt) { | |||
| float deltaPhase = fminf(freq * dt, 0.5f); | |||
| phase += deltaPhase; | |||
| if (phase >= 1.0f) | |||
| phase -= 1.0f; | |||
| if (phase >= 1.f) | |||
| phase -= 1.f; | |||
| } | |||
| float sin() { | |||
| 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 | |||
| 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) { | |||
| return 4.0f * fabsf(x - roundf(x)); | |||
| return 4.f * std::abs(x - std::round(x)); | |||
| } | |||
| float tri() { | |||
| if (offset) | |||
| return tri(invert ? phase - 0.5f : phase); | |||
| 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) { | |||
| return 2.0f * (x - roundf(x)); | |||
| return 2.f * (x - std::round(x)); | |||
| } | |||
| float saw() { | |||
| if (offset) | |||
| return invert ? 2.0f * (1.0f - phase) : 2.0f * phase; | |||
| return invert ? 2.f * (1.f - phase) : 2.f * phase; | |||
| else | |||
| return saw(phase) * (invert ? -1.0f : 1.0f); | |||
| return saw(phase) * (invert ? -1.f : 1.f); | |||
| } | |||
| 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() { | |||
| return sinf(2*M_PI * phase); | |||
| return std::sin(2*M_PI * phase); | |||
| } | |||
| }; | |||
| @@ -96,27 +96,36 @@ struct LFO : Module { | |||
| 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 { | |||
| @@ -124,31 +133,31 @@ struct LFOWidget : ModuleWidget { | |||
| }; | |||
| 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(box.size.x-30, 0))); | |||
| addChild(createWidget<ScrewSilver>(Vec(15, 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)); | |||
| } | |||
| @@ -184,32 +193,37 @@ struct LFO2 : Module { | |||
| 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 { | |||
| @@ -217,25 +231,25 @@ struct LFO2Widget : ModuleWidget { | |||
| }; | |||
| 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(box.size.x-30, 0))); | |||
| addChild(createWidget<ScrewSilver>(Vec(15, 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)); | |||
| } | |||
| @@ -23,12 +23,28 @@ struct Mutes : Module { | |||
| }; | |||
| 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(); | |||
| } | |||
| 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 { | |||
| for (int i = 0; i < NUM_CHANNELS; i++) { | |||
| @@ -37,7 +53,7 @@ struct Mutes : Module { | |||
| } | |||
| void onRandomize() override { | |||
| 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); | |||
| return rootJ; | |||
| } | |||
| void dataFromJson(json_t *rootJ) override { | |||
| // 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> | |||
| struct MuteLight : BASE { | |||
| 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) { | |||
| 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(box.size.x - 30, 0))); | |||
| addChild(createWidget<ScrewSilver>(Vec(15, 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, 28.916)), module, Mutes::MUTE_LIGHT + 1)); | |||
| @@ -38,16 +38,29 @@ struct SEQ3 : Module { | |||
| }; | |||
| 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 */ | |||
| float phase = 0.f; | |||
| int index = 0; | |||
| 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(); | |||
| } | |||
| @@ -59,7 +72,7 @@ struct SEQ3 : Module { | |||
| void onRandomize() override { | |||
| 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) { | |||
| 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; | |||
| this->index = index; | |||
| if (this->index >= numSteps) | |||
| @@ -121,8 +134,8 @@ struct SEQ3 : Module { | |||
| } | |||
| else { | |||
| // 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) { | |||
| setIndex(index + 1); | |||
| } | |||
| @@ -161,41 +174,41 @@ struct SEQ3 : Module { | |||
| struct SEQ3Widget : ModuleWidget { | |||
| 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(box.size.x-30, 0))); | |||
| addChild(createWidget<ScrewSilver>(Vec(15, 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)); | |||
| 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)); | |||
| 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(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(295.4f, 64.4f), module, SEQ3::ROW_LIGHTS + 2)); | |||
| 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++) { | |||
| 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)); | |||
| 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" | |||
| #define BUFFER_SIZE 512 | |||
| static const int BUFFER_SIZE = 512; | |||
| struct Scope : Module { | |||
| enum ParamIds { | |||
| @@ -38,14 +39,82 @@ struct Scope : Module { | |||
| int bufferIndex = 0; | |||
| float frameIndex = 0; | |||
| SchmittTrigger sumTrigger; | |||
| SchmittTrigger extTrigger; | |||
| dsp::SchmittTrigger sumTrigger; | |||
| dsp::SchmittTrigger extTrigger; | |||
| bool lissajous = 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 *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 { | |||
| Scope *module; | |||
| int frame = 0; | |||
| @@ -145,17 +154,17 @@ struct ScopeDisplay : TransparentWidget { | |||
| for (int i = 0; i < BUFFER_SIZE; i++) { | |||
| float v = values[i]; | |||
| 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; | |||
| } | |||
| }; | |||
| Stats statsX, statsY; | |||
| 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) { | |||
| @@ -306,7 +315,7 @@ struct ScopeWidget : ModuleWidget { | |||
| }; | |||
| 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(box.size.x-30, 0))); | |||
| @@ -321,18 +330,18 @@ ScopeWidget::ScopeWidget(Scope *module) : ModuleWidget(module) { | |||
| 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, 296), module, Scope::LISSAJOUS_LIGHT)); | |||
| @@ -22,12 +22,15 @@ struct SequentialSwitch : Module { | |||
| NUM_LIGHTS | |||
| }; | |||
| SchmittTrigger clockTrigger; | |||
| SchmittTrigger resetTrigger; | |||
| dsp::SchmittTrigger clockTrigger; | |||
| dsp::SchmittTrigger resetTrigger; | |||
| 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++) { | |||
| channelFilter[i].rise = 0.01f; | |||
| channelFilter[i].fall = 0.01f; | |||
| @@ -47,7 +50,7 @@ struct SequentialSwitch : Module { | |||
| // Filter channels | |||
| 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 | |||
| @@ -58,7 +61,7 @@ struct SequentialSwitch : Module { | |||
| } | |||
| } | |||
| else { | |||
| float out = 0.0f; | |||
| float out = 0.f; | |||
| for (int i = 0; i < 4; i++) { | |||
| out += channelFilter[i].out * inputs[IN_INPUT + i].value; | |||
| } | |||
| @@ -79,21 +82,21 @@ struct SequentialSwitch1Widget : ModuleWidget { | |||
| SequentialSwitch1Widget::SequentialSwitch1Widget(SequentialSwitch<1> *module) : ModuleWidget(module) { | |||
| 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, 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, 87.7163)), module, TSequentialSwitch::CHANNEL_LIGHT + 1)); | |||
| @@ -111,21 +114,21 @@ struct SequentialSwitch2Widget : ModuleWidget { | |||
| SequentialSwitch2Widget::SequentialSwitch2Widget(SequentialSwitch<2> *module) : ModuleWidget(module) { | |||
| 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, 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, 72.6281)), module, TSequentialSwitch::CHANNEL_LIGHT + 1)); | |||
| @@ -27,8 +27,50 @@ struct Unity : Module { | |||
| 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 { | |||
| 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 { | |||
| @@ -95,33 +99,33 @@ struct UnityWidget : ModuleWidget { | |||
| }; | |||
| 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(box.size.x - 30, 0))); | |||
| addChild(createWidget<ScrewSilver>(Vec(15, 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<YellowLight>>(mm2px(Vec(13.652, 25.163)), module, Unity::VU1_LIGHT + 1)); | |||
| @@ -22,25 +22,28 @@ struct VCA : Module { | |||
| 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 { | |||
| @@ -48,25 +51,25 @@ struct VCAWidget : ModuleWidget { | |||
| }; | |||
| 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(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(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; | |||
| 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 { | |||
| float cv = inputs[CV_INPUT].normalize(10.f) / 10.f; | |||
| if ((int) params[EXP_PARAM].value == 0) | |||
| cv = powf(cv, 4.f); | |||
| cv = std::pow(cv, 4.f); | |||
| lastCv = 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, | |||
| r.size.x, r.size.y / segs - 1.0); | |||
| 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); | |||
| } | |||
| if (segAmplitude > 0.f) { | |||
| nvgFillColor(vg, colorAlpha(COLOR_GREEN, segAmplitude)); | |||
| nvgFillColor(vg, color::alpha(color::GREEN, segAmplitude)); | |||
| nvgFill(vg); | |||
| } | |||
| } | |||
| @@ -147,22 +154,22 @@ struct VCA_1VUKnob : Knob { | |||
| struct VCA_1Widget : ModuleWidget { | |||
| 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(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(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; | |||
| 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" | |||
| inline float clip(float x) { | |||
| return tanhf(x); | |||
| static float clip(float x) { | |||
| return std::tanh(x); | |||
| } | |||
| struct LadderFilter { | |||
| @@ -78,7 +78,14 @@ struct VCF : Module { | |||
| // Decimator<UPSAMPLE, 8> lowpassDecimator; | |||
| // 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 { | |||
| filter.reset(); | |||
| @@ -97,7 +104,7 @@ struct VCF : Module { | |||
| input *= gain; | |||
| // 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 | |||
| 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 | |||
| float pitch = 0.f; | |||
| 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 += 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); | |||
| cutoff = clamp(cutoff, 1.f, 8000.f); | |||
| filter.setCutoff(cutoff); | |||
| /* | |||
| // Process sample | |||
| float dt = engineGetSampleTime() / UPSAMPLE; | |||
| float dt = app()->engine->getSampleTime() / UPSAMPLE; | |||
| float inputBuf[UPSAMPLE]; | |||
| float lowpassBuf[UPSAMPLE]; | |||
| float highpassBuf[UPSAMPLE]; | |||
| @@ -135,7 +142,7 @@ struct VCF : Module { | |||
| 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[HPF_OUTPUT].value = 5.f * filter.highpass; | |||
| } | |||
| @@ -144,29 +151,28 @@ struct VCF : Module { | |||
| struct VCFWidget : ModuleWidget { | |||
| 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(box.size.x - 30, 0))); | |||
| addChild(createWidget<ScrewSilver>(Vec(15, 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"); | |||
| @@ -19,13 +19,20 @@ struct VCMixer : Module { | |||
| 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 { | |||
| float mix = 0.f; | |||
| for (int i = 0; i < 4; i++) { | |||
| 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) | |||
| ch *= clamp(inputs[CV_INPUT + i].value / 10.f, 0.f, 1.f); | |||
| outputs[CH_OUTPUT + i].value = ch; | |||
| @@ -41,35 +48,35 @@ struct VCMixer : Module { | |||
| struct VCMixerWidget : ModuleWidget { | |||
| 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(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(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 | |||
| 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 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 | |||
| float pitchSlew = 0.0f; | |||
| @@ -42,11 +42,11 @@ struct VoltageControlledOscillator { | |||
| } | |||
| else { | |||
| // Quantize coarse knob if digital mode | |||
| pitch = roundf(pitch); | |||
| pitch = std::round(pitch); | |||
| } | |||
| pitch += pitchCv; | |||
| // 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) { | |||
| const float pwMin = 0.01f; | |||
| @@ -101,9 +101,9 @@ struct VoltageControlledOscillator { | |||
| if (analog) { | |||
| // Quadratic approximation of sine, slightly richer harmonics | |||
| 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 | |||
| 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; | |||
| } | |||
| else { | |||
| @@ -211,10 +211,10 @@ void VCO::step() { | |||
| oscillator.analog = params[MODE_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; | |||
| 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.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.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.syncEnabled = inputs[SYNC_INPUT].active; | |||