Browse Source

Update to Rack v1 API

tags/v1.0.1
Andrew Belt 4 years ago
parent
commit
1a10253ae3
15 changed files with 712 additions and 627 deletions
  1. +62
    -49
      src/8vert.cpp
  2. +71
    -67
      src/ADSR.cpp
  3. +85
    -84
      src/Delay.cpp
  4. +0
    -2
      src/Fundamental.cpp
  5. +2
    -1
      src/Fundamental.hpp
  6. +101
    -87
      src/LFO.cpp
  7. +55
    -50
      src/Mutes.cpp
  8. +40
    -27
      src/SEQ3.cpp
  9. +92
    -83
      src/Scope.cpp
  10. +27
    -24
      src/SequentialSwitch.cpp
  11. +65
    -61
      src/Unity.cpp
  12. +44
    -37
      src/VCA.cpp
  13. +27
    -21
      src/VCF.cpp
  14. +29
    -22
      src/VCMixer.cpp
  15. +12
    -12
      src/VCO.cpp

+ 62
- 49
src/8vert.cpp View File

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




+ 71
- 67
src/ADSR.cpp View File

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


+ 85
- 84
src/Delay.cpp View File

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

+ 0
- 2
src/Fundamental.cpp View File

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


+ 2
- 1
src/Fundamental.hpp View File

@@ -1,4 +1,5 @@
#include "rack0.hpp"
#include "rack.hpp"
#include "componentlibrary.hpp"


using namespace rack;


+ 101
- 87
src/LFO.cpp View File

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


+ 55
- 50
src/Mutes.cpp View File

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


+ 40
- 27
src/SEQ3.cpp View File

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


+ 92
- 83
src/Scope.cpp View File

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


+ 27
- 24
src/SequentialSwitch.cpp View File

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


+ 65
- 61
src/Unity.cpp View File

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


+ 44
- 37
src/VCA.cpp View File

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



+ 27
- 21
src/VCF.cpp View File

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

+ 29
- 22
src/VCMixer.cpp View File

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



+ 12
- 12
src/VCO.cpp View File

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