@@ -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); |