Browse Source

v1 migration phase 2

tags/v1.0.1
Andrew Belt 6 years ago
parent
commit
32665b0430
20 changed files with 1045 additions and 1494 deletions
  1. +0
    -1
      src/AudibleInstruments.cpp
  2. +1
    -2
      src/AudibleInstruments.hpp
  3. +49
    -38
      src/Blinds.cpp
  4. +72
    -64
      src/Braids.cpp
  5. +36
    -29
      src/Branches.cpp
  6. +86
    -70
      src/Clouds.cpp
  7. +116
    -85
      src/Elements.cpp
  8. +56
    -47
      src/Frames.cpp
  9. +35
    -33
      src/Kinks.cpp
  10. +36
    -34
      src/Links.cpp
  11. +84
    -66
      src/Marbles.cpp
  12. +0
    -659
      src/Peaks.cpp
  13. +81
    -63
      src/Plaits.cpp
  14. +81
    -66
      src/Rings.cpp
  15. +31
    -22
      src/Shades.cpp
  16. +72
    -51
      src/Stages.cpp
  17. +64
    -54
      src/Tides.cpp
  18. +56
    -40
      src/Tides2.cpp
  19. +48
    -37
      src/Veils.cpp
  20. +41
    -33
      src/Warps.cpp

+ 0
- 1
src/AudibleInstruments.cpp View File

@@ -21,7 +21,6 @@ void init(rack::Plugin *p) {
p->addModel(modelBlinds);
p->addModel(modelVeils);
p->addModel(modelFrames);
// p->addModel(modelPeaks);
p->addModel(modelMarbles);
p->addModel(modelStages);
}

+ 1
- 2
src/AudibleInstruments.hpp View File

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


using namespace rack;
@@ -21,6 +21,5 @@ extern Model *modelBranches;
extern Model *modelBlinds;
extern Model *modelVeils;
extern Model *modelFrames;
extern Model *modelPeaks;
extern Model *modelStages;
extern Model *modelMarbles;

+ 49
- 38
src/Blinds.cpp View File

@@ -43,25 +43,35 @@ struct Blinds : Module {
NUM_LIGHTS
};

Blinds() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
void step() override;
Blinds() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Blinds::GAIN1_PARAM, -1.0, 1.0, 0.0);
configParam(Blinds::GAIN2_PARAM, -1.0, 1.0, 0.0);
configParam(Blinds::GAIN3_PARAM, -1.0, 1.0, 0.0);
configParam(Blinds::GAIN4_PARAM, -1.0, 1.0, 0.0);
configParam(Blinds::MOD1_PARAM, -1.0, 1.0, 0.0);
configParam(Blinds::MOD2_PARAM, -1.0, 1.0, 0.0);
configParam(Blinds::MOD3_PARAM, -1.0, 1.0, 0.0);
configParam(Blinds::MOD4_PARAM, -1.0, 1.0, 0.0);
}
void process(const ProcessArgs &args) override;
};


void Blinds::step() {
void Blinds::process(const ProcessArgs &args) {
float out = 0.0;

for (int i = 0; i < 4; i++) {
float g = params[GAIN1_PARAM + i].value;
g += params[MOD1_PARAM + i].value * inputs[CV1_INPUT + i].value / 5.0;
float g = params[GAIN1_PARAM + i].getValue();
g += params[MOD1_PARAM + i].getValue() * inputs[CV1_INPUT + i].getVoltage() / 5.0;
g = clamp(g, -2.0f, 2.0f);
lights[CV1_POS_LIGHT + 2*i].setBrightnessSmooth(fmaxf(0.0, g));
lights[CV1_NEG_LIGHT + 2*i].setBrightnessSmooth(fmaxf(0.0, -g));
out += g * inputs[IN1_INPUT + i].normalize(5.0);
lights[OUT1_POS_LIGHT + 2*i].setBrightnessSmooth(fmaxf(0.0, out / 5.0));
lights[OUT1_NEG_LIGHT + 2*i].setBrightnessSmooth(fmaxf(0.0, -out / 5.0));
if (outputs[OUT1_OUTPUT + i].active) {
outputs[OUT1_OUTPUT + i].value = out;
lights[CV1_POS_LIGHT + 2*i].setSmoothBrightness(fmaxf(0.0, g), args.sampleTime);
lights[CV1_NEG_LIGHT + 2*i].setSmoothBrightness(fmaxf(0.0, -g), args.sampleTime);
out += g * inputs[IN1_INPUT + i].getNormalVoltage(5.0);
lights[OUT1_POS_LIGHT + 2*i].setSmoothBrightness(fmaxf(0.0, out / 5.0), args.sampleTime);
lights[OUT1_NEG_LIGHT + 2*i].setSmoothBrightness(fmaxf(0.0, -out / 5.0), args.sampleTime);
if (outputs[OUT1_OUTPUT + i].isConnected()) {
outputs[OUT1_OUTPUT + i].setVoltage(out);
out = 0.0;
}
}
@@ -69,38 +79,39 @@ void Blinds::step() {


struct BlindsWidget : ModuleWidget {
BlindsWidget(Blinds *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Blinds.svg")));
BlindsWidget(Blinds *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Blinds.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(150, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));
addChild(createWidget<ScrewSilver>(Vec(150, 365)));

addParam(createParam<Rogan1PSWhite>(Vec(8, 52), module, Blinds::GAIN1_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(8, 131), module, Blinds::GAIN2_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(8, 210), module, Blinds::GAIN3_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(8, 288), module, Blinds::GAIN4_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(72, 63), module, Blinds::MOD1_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(72, 142), module, Blinds::MOD2_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(72, 221), module, Blinds::MOD3_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(72, 300), module, Blinds::MOD4_PARAM, -1.0, 1.0, 0.0));
addInput(createPort<PJ301MPort>(Vec(110, 41), PortWidget::INPUT, module, Blinds::IN1_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 120), PortWidget::INPUT, module, Blinds::IN2_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 198), PortWidget::INPUT, module, Blinds::IN3_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 277), PortWidget::INPUT, module, Blinds::IN4_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 80), PortWidget::INPUT, module, Blinds::CV1_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 159), PortWidget::INPUT, module, Blinds::CV2_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 238), PortWidget::INPUT, module, Blinds::CV3_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 316), PortWidget::INPUT, module, Blinds::CV4_INPUT));
addOutput(createPort<PJ301MPort>(Vec(144, 41), PortWidget::OUTPUT, module, Blinds::OUT1_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(144, 120), PortWidget::OUTPUT, module, Blinds::OUT2_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(144, 198), PortWidget::OUTPUT, module, Blinds::OUT3_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(144, 277), PortWidget::OUTPUT, module, Blinds::OUT4_OUTPUT));
addParam(createParam<Rogan1PSWhite>(Vec(8, 52), module, Blinds::GAIN1_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(8, 131), module, Blinds::GAIN2_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(8, 210), module, Blinds::GAIN3_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(8, 288), module, Blinds::GAIN4_PARAM));
addParam(createParam<Trimpot>(Vec(72, 63), module, Blinds::MOD1_PARAM));
addParam(createParam<Trimpot>(Vec(72, 142), module, Blinds::MOD2_PARAM));
addParam(createParam<Trimpot>(Vec(72, 221), module, Blinds::MOD3_PARAM));
addParam(createParam<Trimpot>(Vec(72, 300), module, Blinds::MOD4_PARAM));
addInput(createInput<PJ301MPort>(Vec(110, 41), module, Blinds::IN1_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 120), module, Blinds::IN2_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 198), module, Blinds::IN3_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 277), module, Blinds::IN4_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 80), module, Blinds::CV1_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 159), module, Blinds::CV2_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 238), module, Blinds::CV3_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 316), module, Blinds::CV4_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(144, 41), module, Blinds::OUT1_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(144, 120), module, Blinds::OUT2_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(144, 198), module, Blinds::OUT3_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(144, 277), module, Blinds::OUT4_OUTPUT));

addChild(createLight<SmallLight<GreenRedLight>>(Vec(78, 96), module, Blinds::CV1_POS_LIGHT));
addChild(createLight<SmallLight<GreenRedLight>>(Vec(78, 175), module, Blinds::CV2_POS_LIGHT));


+ 72
- 64
src/Braids.cpp View File

@@ -33,13 +33,35 @@ struct Braids : Module {
braids::VcoJitterSource jitter_source;
braids::SignatureWaveshaper ws;

SampleRateConverter<1> src;
DoubleRingBuffer<Frame<1>, 256> outputBuffer;
dsp::SampleRateConverter<1> src;
dsp::DoubleRingBuffer<dsp::Frame<1>, 256> outputBuffer;
bool lastTrig = false;
bool lowCpu = false;

Braids();
void step() override;
Braids() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
configParam(Braids::SHAPE_PARAM, 0.0, 1.0, 0.0);
configParam(Braids::FINE_PARAM, -1.0, 1.0, 0.0);
configParam(Braids::COARSE_PARAM, -2.0, 2.0, 0.0);
configParam(Braids::FM_PARAM, -1.0, 1.0, 0.0);
configParam(Braids::TIMBRE_PARAM, 0.0, 1.0, 0.5);
configParam(Braids::MODULATION_PARAM, -1.0, 1.0, 0.0);
configParam(Braids::COLOR_PARAM, 0.0, 1.0, 0.5);

memset(&osc, 0, sizeof(osc));
osc.Init();
memset(&jitter_source, 0, sizeof(jitter_source));
jitter_source.Init();
memset(&ws, 0, sizeof(ws));
ws.Init(0x0000);
memset(&settings, 0, sizeof(settings));

// List of supported settings
settings.meta_modulation = 0;
settings.vco_drift = 0;
settings.signature = 0;
}
void process(const ProcessArgs &args) override;
void setShape(int shape);

json_t *dataToJson() override {
@@ -77,24 +99,9 @@ struct Braids : Module {
};


Braids::Braids() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
memset(&osc, 0, sizeof(osc));
osc.Init();
memset(&jitter_source, 0, sizeof(jitter_source));
jitter_source.Init();
memset(&ws, 0, sizeof(ws));
ws.Init(0x0000);
memset(&settings, 0, sizeof(settings));

// List of supported settings
settings.meta_modulation = 0;
settings.vco_drift = 0;
settings.signature = 0;
}

void Braids::step() {
void Braids::process(const ProcessArgs &args) {
// Trigger
bool trig = inputs[TRIG_INPUT].value >= 1.0;
bool trig = inputs[TRIG_INPUT].getVoltage() >= 1.0;
if (!lastTrig && trig) {
osc.Strike();
}
@@ -102,10 +109,10 @@ void Braids::step() {

// Render frames
if (outputBuffer.empty()) {
float fm = params[FM_PARAM].value * inputs[FM_INPUT].value;
float fm = params[FM_PARAM].getValue() * inputs[FM_INPUT].getVoltage();

// Set shape
int shape = roundf(params[SHAPE_PARAM].value * braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META);
int shape = roundf(params[SHAPE_PARAM].getValue() * braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META);
if (settings.meta_modulation) {
shape += roundf(fm / 10.0 * braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META);
}
@@ -115,18 +122,18 @@ void Braids::step() {
osc.set_shape((braids::MacroOscillatorShape) settings.shape);

// Set timbre/modulation
float timbre = params[TIMBRE_PARAM].value + params[MODULATION_PARAM].value * inputs[TIMBRE_INPUT].value / 5.0;
float modulation = params[COLOR_PARAM].value + inputs[COLOR_INPUT].value / 5.0;
float timbre = params[TIMBRE_PARAM].getValue() + params[MODULATION_PARAM].getValue() * inputs[TIMBRE_INPUT].getVoltage() / 5.0;
float modulation = params[COLOR_PARAM].getValue() + inputs[COLOR_INPUT].getVoltage() / 5.0;
int16_t param1 = rescale(clamp(timbre, 0.0f, 1.0f), 0.0f, 1.0f, 0, INT16_MAX);
int16_t param2 = rescale(clamp(modulation, 0.0f, 1.0f), 0.0f, 1.0f, 0, INT16_MAX);
osc.set_parameters(param1, param2);

// Set pitch
float pitchV = inputs[PITCH_INPUT].value + params[COARSE_PARAM].value + params[FINE_PARAM].value / 12.0;
float pitchV = inputs[PITCH_INPUT].getVoltage() + params[COARSE_PARAM].getValue() + params[FINE_PARAM].getValue() / 12.0;
if (!settings.meta_modulation)
pitchV += fm;
if (lowCpu)
pitchV += log2f(96000.f * engineGetSampleTime());
pitchV += log2f(96000.f * args.sampleTime);
int32_t pitch = (pitchV * 12.0 + 60) * 128;
pitch += jitter_source.Render(settings.vco_drift);
pitch = clamp(pitch, 0, 16383);
@@ -149,18 +156,18 @@ void Braids::step() {

if (lowCpu) {
for (int i = 0; i < 24; i++) {
Frame<1> f;
dsp::Frame<1> f;
f.samples[0] = render_buffer[i] / 32768.0;
outputBuffer.push(f);
}
}
else {
// Sample rate convert
Frame<1> in[24];
dsp::Frame<1> in[24];
for (int i = 0; i < 24; i++) {
in[i].samples[0] = render_buffer[i] / 32768.0;
}
src.setRates(96000, engineGetSampleRate());
src.setRates(96000, args.sampleRate);

int inLen = 24;
int outLen = outputBuffer.capacity();
@@ -171,8 +178,8 @@ void Braids::step() {

// Output
if (!outputBuffer.empty()) {
Frame<1> f = outputBuffer.shift();
outputs[OUT_OUTPUT].value = 5.0 * f.samples[0];
dsp::Frame<1> f = outputBuffer.shift();
outputs[OUT_OUTPUT].setVoltage(5.0 * f.samples[0]);
}
}

@@ -233,33 +240,33 @@ struct BraidsDisplay : TransparentWidget {
std::shared_ptr<Font> font;

BraidsDisplay() {
font = Font::load(assetPlugin(pluginInstance, "res/hdad-segment14-1.002/Segment14.ttf"));
font = APP->window->loadFont(asset::plugin(pluginInstance, "res/hdad-segment14-1.002/Segment14.ttf"));
}

void draw(NVGcontext *vg) override {
void draw(const DrawArgs &args) override {
int shape = module ? module->settings.shape : 0;

// Background
NVGcolor backgroundColor = nvgRGB(0x38, 0x38, 0x38);
NVGcolor borderColor = nvgRGB(0x10, 0x10, 0x10);
nvgBeginPath(vg);
nvgRoundedRect(vg, 0.0, 0.0, box.size.x, box.size.y, 5.0);
nvgFillColor(vg, backgroundColor);
nvgFill(vg);
nvgStrokeWidth(vg, 1.0);
nvgStrokeColor(vg, borderColor);
nvgStroke(vg);
nvgFontSize(vg, 36);
nvgFontFaceId(vg, font->handle);
nvgTextLetterSpacing(vg, 2.5);
nvgBeginPath(args.vg);
nvgRoundedRect(args.vg, 0.0, 0.0, box.size.x, box.size.y, 5.0);
nvgFillColor(args.vg, backgroundColor);
nvgFill(args.vg);
nvgStrokeWidth(args.vg, 1.0);
nvgStrokeColor(args.vg, borderColor);
nvgStroke(args.vg);
nvgFontSize(args.vg, 36);
nvgFontFaceId(args.vg, font->handle);
nvgTextLetterSpacing(args.vg, 2.5);

Vec textPos = Vec(10, 48);
NVGcolor textColor = nvgRGB(0xaf, 0xd2, 0x2c);
nvgFillColor(vg, nvgTransRGBA(textColor, 16));
nvgText(vg, textPos.x, textPos.y, "~~~~", NULL);
nvgFillColor(vg, textColor);
nvgText(vg, textPos.x, textPos.y, algo_values[shape], NULL);
nvgFillColor(args.vg, nvgTransRGBA(textColor, 16));
nvgText(args.vg, textPos.x, textPos.y, "~~~~", NULL);
nvgFillColor(args.vg, textColor);
nvgText(args.vg, textPos.x, textPos.y, algo_values[shape], NULL);
}
};

@@ -291,8 +298,9 @@ struct BraidsLowCpuItem : MenuItem {


struct BraidsWidget : ModuleWidget {
BraidsWidget(Braids *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Braids.svg")));
BraidsWidget(Braids *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Braids.svg")));

{
BraidsDisplay *display = new BraidsDisplay();
@@ -307,22 +315,22 @@ struct BraidsWidget : ModuleWidget {
addChild(createWidget<ScrewSilver>(Vec(15, 365)));
addChild(createWidget<ScrewSilver>(Vec(210, 365)));

addParam(createParam<Rogan2SGray>(Vec(176, 59), module, Braids::SHAPE_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan2SGray>(Vec(176, 59), module, Braids::SHAPE_PARAM));

addParam(createParam<Rogan2PSWhite>(Vec(19, 138), module, Braids::FINE_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Rogan2PSWhite>(Vec(97, 138), module, Braids::COARSE_PARAM, -2.0, 2.0, 0.0));
addParam(createParam<Rogan2PSWhite>(Vec(176, 138), module, Braids::FM_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Rogan2PSWhite>(Vec(19, 138), module, Braids::FINE_PARAM));
addParam(createParam<Rogan2PSWhite>(Vec(97, 138), module, Braids::COARSE_PARAM));
addParam(createParam<Rogan2PSWhite>(Vec(176, 138), module, Braids::FM_PARAM));

addParam(createParam<Rogan2PSGreen>(Vec(19, 217), module, Braids::TIMBRE_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan2PSGreen>(Vec(97, 217), module, Braids::MODULATION_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Rogan2PSRed>(Vec(176, 217), module, Braids::COLOR_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan2PSGreen>(Vec(19, 217), module, Braids::TIMBRE_PARAM));
addParam(createParam<Rogan2PSGreen>(Vec(97, 217), module, Braids::MODULATION_PARAM));
addParam(createParam<Rogan2PSRed>(Vec(176, 217), module, Braids::COLOR_PARAM));

addInput(createPort<PJ301MPort>(Vec(10, 316), PortWidget::INPUT, module, Braids::TRIG_INPUT));
addInput(createPort<PJ301MPort>(Vec(47, 316), PortWidget::INPUT, module, Braids::PITCH_INPUT));
addInput(createPort<PJ301MPort>(Vec(84, 316), PortWidget::INPUT, module, Braids::FM_INPUT));
addInput(createPort<PJ301MPort>(Vec(122, 316), PortWidget::INPUT, module, Braids::TIMBRE_INPUT));
addInput(createPort<PJ301MPort>(Vec(160, 316), PortWidget::INPUT, module, Braids::COLOR_INPUT));
addOutput(createPort<PJ301MPort>(Vec(205, 316), PortWidget::OUTPUT, module, Braids::OUT_OUTPUT));
addInput(createInput<PJ301MPort>(Vec(10, 316), module, Braids::TRIG_INPUT));
addInput(createInput<PJ301MPort>(Vec(47, 316), module, Braids::PITCH_INPUT));
addInput(createInput<PJ301MPort>(Vec(84, 316), module, Braids::FM_INPUT));
addInput(createInput<PJ301MPort>(Vec(122, 316), module, Braids::TIMBRE_INPUT));
addInput(createInput<PJ301MPort>(Vec(160, 316), module, Braids::COLOR_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(205, 316), module, Braids::OUT_OUTPUT));
}

void appendContextMenu(Menu *menu) override {


+ 36
- 29
src/Branches.cpp View File

@@ -31,12 +31,18 @@ struct Branches : Module {
NUM_LIGHTS
};

SchmittTrigger gateTriggers[2];
SchmittTrigger modeTriggers[2];
dsp::SchmittTrigger gateTriggers[2];
dsp::SchmittTrigger modeTriggers[2];
bool modes[2] = {};
bool outcomes[2] = {};

Branches() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
Branches() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Branches::THRESHOLD1_PARAM, 0.0, 1.0, 0.5);
configParam(Branches::MODE1_PARAM, 0.0, 1.0, 0.0);
configParam(Branches::THRESHOLD2_PARAM, 0.0, 1.0, 0.5);
configParam(Branches::MODE2_PARAM, 0.0, 1.0, 0.0);
}

json_t *dataToJson() override {
json_t *rootJ = json_object();
@@ -59,7 +65,7 @@ struct Branches : Module {
}
}

void step() override;
void process(const ProcessArgs &args) override;

void onReset() override {
for (int i = 0; i < 2; i++) {
@@ -70,20 +76,20 @@ struct Branches : Module {
};


void Branches::step() {
void Branches::process(const ProcessArgs &args) {
float gate = 0.0;
for (int i = 0; i < 2; i++) {
// mode button
if (modeTriggers[i].process(params[MODE1_PARAM + i].value))
if (modeTriggers[i].process(params[MODE1_PARAM + i].getValue()))
modes[i] = !modes[i];

if (inputs[IN1_INPUT + i].active)
gate = inputs[IN1_INPUT + i].value;
if (inputs[IN1_INPUT + i].isConnected())
gate = inputs[IN1_INPUT + i].getVoltage();

if (gateTriggers[i].process(gate)) {
// trigger
float r = randomUniform();
float threshold = clamp(params[THRESHOLD1_PARAM + i].value + inputs[P1_INPUT + i].value / 10.f, 0.f, 1.f);
float r = random::uniform();
float threshold = clamp(params[THRESHOLD1_PARAM + i].getValue() + inputs[P1_INPUT + i].getVoltage() / 10.f, 0.f, 1.f);
bool toss = (r < threshold);
if (!modes[i]) {
// direct modes
@@ -100,36 +106,37 @@ void Branches::step() {
lights[STATE1_NEG_LIGHT + 2*i].value = 1.0;
}

lights[STATE1_POS_LIGHT + 2*i].value *= 1.0 - engineGetSampleTime() * 15.0;
lights[STATE1_NEG_LIGHT + 2*i].value *= 1.0 - engineGetSampleTime() * 15.0;
lights[STATE1_POS_LIGHT + 2*i].value *= 1.0 - args.sampleTime * 15.0;
lights[STATE1_NEG_LIGHT + 2*i].value *= 1.0 - args.sampleTime * 15.0;
lights[MODE1_LIGHT + i].value = modes[i] ? 1.0 : 0.0;

outputs[OUT1A_OUTPUT + i].value = outcomes[i] ? 0.0 : gate;
outputs[OUT1B_OUTPUT + i].value = outcomes[i] ? gate : 0.0;
outputs[OUT1A_OUTPUT + i].setVoltage(outcomes[i] ? 0.0 : gate);
outputs[OUT1B_OUTPUT + i].setVoltage(outcomes[i] ? gate : 0.0);
}
}


struct BranchesWidget : ModuleWidget {
BranchesWidget(Branches *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Branches.svg")));
BranchesWidget(Branches *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Branches.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));

addParam(createParam<Rogan1PSRed>(Vec(24, 64), module, Branches::THRESHOLD1_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<TL1105>(Vec(69, 58), module, Branches::MODE1_PARAM, 0.0, 1.0, 0.0));
addInput(createPort<PJ301MPort>(Vec(9, 122), PortWidget::INPUT, module, Branches::IN1_INPUT));
addInput(createPort<PJ301MPort>(Vec(55, 122), PortWidget::INPUT, module, Branches::P1_INPUT));
addOutput(createPort<PJ301MPort>(Vec(9, 160), PortWidget::OUTPUT, module, Branches::OUT1A_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(55, 160), PortWidget::OUTPUT, module, Branches::OUT1B_OUTPUT));
addParam(createParam<Rogan1PSGreen>(Vec(24, 220), module, Branches::THRESHOLD2_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<TL1105>(Vec(69, 214), module, Branches::MODE2_PARAM, 0.0, 1.0, 0.0));
addInput(createPort<PJ301MPort>(Vec(9, 278), PortWidget::INPUT, module, Branches::IN2_INPUT));
addInput(createPort<PJ301MPort>(Vec(55, 278), PortWidget::INPUT, module, Branches::P2_INPUT));
addOutput(createPort<PJ301MPort>(Vec(9, 316), PortWidget::OUTPUT, module, Branches::OUT2A_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(55, 316), PortWidget::OUTPUT, module, Branches::OUT2B_OUTPUT));
addParam(createParam<Rogan1PSRed>(Vec(24, 64), module, Branches::THRESHOLD1_PARAM));
addParam(createParam<TL1105>(Vec(69, 58), module, Branches::MODE1_PARAM));
addInput(createInput<PJ301MPort>(Vec(9, 122), module, Branches::IN1_INPUT));
addInput(createInput<PJ301MPort>(Vec(55, 122), module, Branches::P1_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(9, 160), module, Branches::OUT1A_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(55, 160), module, Branches::OUT1B_OUTPUT));
addParam(createParam<Rogan1PSGreen>(Vec(24, 220), module, Branches::THRESHOLD2_PARAM));
addParam(createParam<TL1105>(Vec(69, 214), module, Branches::MODE2_PARAM));
addInput(createInput<PJ301MPort>(Vec(9, 278), module, Branches::IN2_INPUT));
addInput(createInput<PJ301MPort>(Vec(55, 278), module, Branches::P2_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(9, 316), module, Branches::OUT2A_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(55, 316), module, Branches::OUT2B_OUTPUT));

addChild(createLight<SmallLight<GreenRedLight>>(Vec(40, 169), module, Branches::STATE1_POS_LIGHT));
addChild(createLight<SmallLight<GreenRedLight>>(Vec(40, 325), module, Branches::STATE2_POS_LIGHT));


+ 86
- 70
src/Clouds.cpp View File

@@ -46,10 +46,10 @@ struct Clouds : Module {
NUM_LIGHTS
};

SampleRateConverter<2> inputSrc;
SampleRateConverter<2> outputSrc;
DoubleRingBuffer<Frame<2>, 256> inputBuffer;
DoubleRingBuffer<Frame<2>, 256> outputBuffer;
dsp::SampleRateConverter<2> inputSrc;
dsp::SampleRateConverter<2> outputSrc;
dsp::DoubleRingBuffer<dsp::Frame<2>, 256> inputBuffer;
dsp::DoubleRingBuffer<dsp::Frame<2>, 256> outputBuffer;

uint8_t *block_mem;
uint8_t *block_ccm;
@@ -57,9 +57,9 @@ struct Clouds : Module {

bool triggered = false;

SchmittTrigger freezeTrigger;
dsp::SchmittTrigger freezeTrigger;
bool freeze = false;
SchmittTrigger blendTrigger;
dsp::SchmittTrigger blendTrigger;
int blendMode = 0;

clouds::PlaybackMode playback;
@@ -67,7 +67,7 @@ struct Clouds : Module {

Clouds();
~Clouds();
void step() override;
void process(const ProcessArgs &args) override;

void onReset() override {
freeze = false;
@@ -105,7 +105,22 @@ struct Clouds : Module {
};


Clouds::Clouds() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
Clouds::Clouds() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Clouds::POSITION_PARAM, 0.0, 1.0, 0.5);
configParam(Clouds::SIZE_PARAM, 0.0, 1.0, 0.5);
configParam(Clouds::PITCH_PARAM, -2.0, 2.0, 0.0);
configParam(Clouds::IN_GAIN_PARAM, 0.0, 1.0, 0.5);
configParam(Clouds::DENSITY_PARAM, 0.0, 1.0, 0.5);
configParam(Clouds::TEXTURE_PARAM, 0.0, 1.0, 0.5);
configParam(Clouds::BLEND_PARAM, 0.0, 1.0, 0.5);
configParam(Clouds::SPREAD_PARAM, 0.0, 1.0, 0.0);
configParam(Clouds::FEEDBACK_PARAM, 0.0, 1.0, 0.0);
configParam(Clouds::REVERB_PARAM, 0.0, 1.0, 0.0);
configParam(Clouds::FREEZE_PARAM, 0.0, 1.0, 0.0);
configParam(Clouds::MODE_PARAM, 0.0, 1.0, 0.0);
configParam(Clouds::LOAD_PARAM, 0.0, 1.0, 0.0);

const int memLen = 118784;
const int ccmLen = 65536 - 128;
block_mem = new uint8_t[memLen]();
@@ -123,24 +138,24 @@ Clouds::~Clouds() {
delete[] block_ccm;
}

void Clouds::step() {
void Clouds::process(const ProcessArgs &args) {
// Get input
Frame<2> inputFrame = {};
dsp::Frame<2> inputFrame = {};
if (!inputBuffer.full()) {
inputFrame.samples[0] = inputs[IN_L_INPUT].value * params[IN_GAIN_PARAM].value / 5.0;
inputFrame.samples[1] = inputs[IN_R_INPUT].active ? inputs[IN_R_INPUT].value * params[IN_GAIN_PARAM].value / 5.0 : inputFrame.samples[0];
inputFrame.samples[0] = inputs[IN_L_INPUT].getVoltage() * params[IN_GAIN_PARAM].getValue() / 5.0;
inputFrame.samples[1] = inputs[IN_R_INPUT].isConnected() ? inputs[IN_R_INPUT].getVoltage() * params[IN_GAIN_PARAM].getValue() / 5.0 : inputFrame.samples[0];
inputBuffer.push(inputFrame);
}

if (freezeTrigger.process(params[FREEZE_PARAM].value)) {
if (freezeTrigger.process(params[FREEZE_PARAM].getValue())) {
freeze ^= true;
}
if (blendTrigger.process(params[MODE_PARAM].value)) {
if (blendTrigger.process(params[MODE_PARAM].getValue())) {
blendMode = (blendMode + 1) % 4;
}

// Trigger
if (inputs[TRIG_INPUT].value >= 1.0) {
if (inputs[TRIG_INPUT].getVoltage() >= 1.0) {
triggered = true;
}

@@ -149,8 +164,8 @@ void Clouds::step() {
clouds::ShortFrame input[32] = {};
// Convert input buffer
{
inputSrc.setRates(engineGetSampleRate(), 32000);
Frame<2> inputFrames[32];
inputSrc.setRates(args.sampleRate, 32000);
dsp::Frame<2> inputFrames[32];
int inLen = inputBuffer.size();
int outLen = 32;
inputSrc.process(inputBuffer.startData(), &inLen, inputFrames, &outLen);
@@ -171,19 +186,19 @@ void Clouds::step() {
clouds::Parameters *p = processor->mutable_parameters();
p->trigger = triggered;
p->gate = triggered;
p->freeze = freeze || (inputs[FREEZE_INPUT].value >= 1.0);
p->position = clamp(params[POSITION_PARAM].value + inputs[POSITION_INPUT].value / 5.0f, 0.0f, 1.0f);
p->size = clamp(params[SIZE_PARAM].value + inputs[SIZE_INPUT].value / 5.0f, 0.0f, 1.0f);
p->pitch = clamp((params[PITCH_PARAM].value + inputs[PITCH_INPUT].value) * 12.0f, -48.0f, 48.0f);
p->density = clamp(params[DENSITY_PARAM].value + inputs[DENSITY_INPUT].value / 5.0f, 0.0f, 1.0f);
p->texture = clamp(params[TEXTURE_PARAM].value + inputs[TEXTURE_INPUT].value / 5.0f, 0.0f, 1.0f);
p->dry_wet = params[BLEND_PARAM].value;
p->stereo_spread = params[SPREAD_PARAM].value;
p->feedback = params[FEEDBACK_PARAM].value;
p->freeze = freeze || (inputs[FREEZE_INPUT].getVoltage() >= 1.0);
p->position = clamp(params[POSITION_PARAM].getValue() + inputs[POSITION_INPUT].getVoltage() / 5.0f, 0.0f, 1.0f);
p->size = clamp(params[SIZE_PARAM].getValue() + inputs[SIZE_INPUT].getVoltage() / 5.0f, 0.0f, 1.0f);
p->pitch = clamp((params[PITCH_PARAM].getValue() + inputs[PITCH_INPUT].getVoltage()) * 12.0f, -48.0f, 48.0f);
p->density = clamp(params[DENSITY_PARAM].getValue() + inputs[DENSITY_INPUT].getVoltage() / 5.0f, 0.0f, 1.0f);
p->texture = clamp(params[TEXTURE_PARAM].getValue() + inputs[TEXTURE_INPUT].getVoltage() / 5.0f, 0.0f, 1.0f);
p->dry_wet = params[BLEND_PARAM].getValue();
p->stereo_spread = params[SPREAD_PARAM].getValue();
p->feedback = params[FEEDBACK_PARAM].getValue();
// TODO
// Why doesn't dry audio get reverbed?
p->reverb = params[REVERB_PARAM].value;
float blend = inputs[BLEND_INPUT].value / 5.0f;
p->reverb = params[REVERB_PARAM].getValue();
float blend = inputs[BLEND_INPUT].getVoltage() / 5.0f;
switch (blendMode) {
case 0:
p->dry_wet += blend;
@@ -208,13 +223,13 @@ void Clouds::step() {

// Convert output buffer
{
Frame<2> outputFrames[32];
dsp::Frame<2> outputFrames[32];
for (int i = 0; i < 32; i++) {
outputFrames[i].samples[0] = output[i].l / 32768.0;
outputFrames[i].samples[1] = output[i].r / 32768.0;
}

outputSrc.setRates(32000, engineGetSampleRate());
outputSrc.setRates(32000, args.sampleRate);
int inLen = 32;
int outLen = outputBuffer.capacity();
outputSrc.process(outputFrames, &inLen, outputBuffer.endData(), &outLen);
@@ -225,28 +240,28 @@ void Clouds::step() {
}

// Set output
Frame<2> outputFrame = {};
dsp::Frame<2> outputFrame = {};
if (!outputBuffer.empty()) {
outputFrame = outputBuffer.shift();
outputs[OUT_L_OUTPUT].value = 5.0 * outputFrame.samples[0];
outputs[OUT_R_OUTPUT].value = 5.0 * outputFrame.samples[1];
outputs[OUT_L_OUTPUT].setVoltage(5.0 * outputFrame.samples[0]);
outputs[OUT_R_OUTPUT].setVoltage(5.0 * outputFrame.samples[1]);
}

// Lights
clouds::Parameters *p = processor->mutable_parameters();
VUMeter vuMeter;
dsp::VuMeter vuMeter;
vuMeter.dBInterval = 6.0;
Frame<2> lightFrame = p->freeze ? outputFrame : inputFrame;
dsp::Frame<2> lightFrame = p->freeze ? outputFrame : inputFrame;
vuMeter.setValue(fmaxf(fabsf(lightFrame.samples[0]), fabsf(lightFrame.samples[1])));
lights[FREEZE_LIGHT].setBrightness(p->freeze ? 0.75 : 0.0);
lights[MIX_GREEN_LIGHT].setBrightnessSmooth(vuMeter.getBrightness(3));
lights[PAN_GREEN_LIGHT].setBrightnessSmooth(vuMeter.getBrightness(2));
lights[FEEDBACK_GREEN_LIGHT].setBrightnessSmooth(vuMeter.getBrightness(1));
lights[MIX_GREEN_LIGHT].setSmoothBrightness(vuMeter.getBrightness(3), args.sampleTime);
lights[PAN_GREEN_LIGHT].setSmoothBrightness(vuMeter.getBrightness(2), args.sampleTime);
lights[FEEDBACK_GREEN_LIGHT].setSmoothBrightness(vuMeter.getBrightness(1), args.sampleTime);
lights[REVERB_GREEN_LIGHT].setBrightness(0.0);
lights[MIX_RED_LIGHT].setBrightness(0.0);
lights[PAN_RED_LIGHT].setBrightness(0.0);
lights[FEEDBACK_RED_LIGHT].setBrightnessSmooth(vuMeter.getBrightness(1));
lights[REVERB_RED_LIGHT].setBrightnessSmooth(vuMeter.getBrightness(0));
lights[FEEDBACK_RED_LIGHT].setSmoothBrightness(vuMeter.getBrightness(1), args.sampleTime);
lights[REVERB_RED_LIGHT].setSmoothBrightness(vuMeter.getBrightness(0), args.sampleTime);
}


@@ -254,7 +269,7 @@ void Clouds::step() {
struct FreezeLight : YellowLight {
FreezeLight() {
box.size = Vec(28-6, 28-6);
bgColor = COLOR_BLACK_TRANSPARENT;
bgColor = color::BLACK_TRANSPARENT;
}
};

@@ -304,47 +319,48 @@ struct CloudsWidget : ModuleWidget {
ParamWidget *feedbackParam;
ParamWidget *reverbParam;

CloudsWidget(Clouds *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Clouds.svg")));
CloudsWidget(Clouds *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Clouds.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(240, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));
addChild(createWidget<ScrewSilver>(Vec(240, 365)));

addParam(createParam<Rogan3PSRed>(Vec(27, 93), module, Clouds::POSITION_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan3PSGreen>(Vec(108, 93), module, Clouds::SIZE_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan3PSWhite>(Vec(190, 93), module, Clouds::PITCH_PARAM, -2.0, 2.0, 0.0));
addParam(createParam<Rogan3PSRed>(Vec(27, 93), module, Clouds::POSITION_PARAM));
addParam(createParam<Rogan3PSGreen>(Vec(108, 93), module, Clouds::SIZE_PARAM));
addParam(createParam<Rogan3PSWhite>(Vec(190, 93), module, Clouds::PITCH_PARAM));

addParam(createParam<Rogan1PSRed>(Vec(14, 180), module, Clouds::IN_GAIN_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSRed>(Vec(81, 180), module, Clouds::DENSITY_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSGreen>(Vec(146, 180), module, Clouds::TEXTURE_PARAM, 0.0, 1.0, 0.5));
blendParam = createParam<Rogan1PSWhite>(Vec(213, 180), module, Clouds::BLEND_PARAM, 0.0, 1.0, 0.5);
addParam(createParam<Rogan1PSRed>(Vec(14, 180), module, Clouds::IN_GAIN_PARAM));
addParam(createParam<Rogan1PSRed>(Vec(81, 180), module, Clouds::DENSITY_PARAM));
addParam(createParam<Rogan1PSGreen>(Vec(146, 180), module, Clouds::TEXTURE_PARAM));
blendParam = createParam<Rogan1PSWhite>(Vec(213, 180), module, Clouds::BLEND_PARAM);
addParam(blendParam);
spreadParam = createParam<Rogan1PSRed>(Vec(213, 180), module, Clouds::SPREAD_PARAM, 0.0, 1.0, 0.0);
spreadParam = createParam<Rogan1PSRed>(Vec(213, 180), module, Clouds::SPREAD_PARAM);
addParam(spreadParam);
feedbackParam = createParam<Rogan1PSGreen>(Vec(213, 180), module, Clouds::FEEDBACK_PARAM, 0.0, 1.0, 0.0);
feedbackParam = createParam<Rogan1PSGreen>(Vec(213, 180), module, Clouds::FEEDBACK_PARAM);
addParam(feedbackParam);
reverbParam = createParam<Rogan1PSBlue>(Vec(213, 180), module, Clouds::REVERB_PARAM, 0.0, 1.0, 0.0);
reverbParam = createParam<Rogan1PSBlue>(Vec(213, 180), module, Clouds::REVERB_PARAM);
addParam(reverbParam);

addParam(createParam<CKD6>(Vec(12, 43), module, Clouds::FREEZE_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<TL1105>(Vec(211, 50), module, Clouds::MODE_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<TL1105>(Vec(239, 50), module, Clouds::LOAD_PARAM, 0.0, 1.0, 0.0));
addInput(createPort<PJ301MPort>(Vec(15, 274), PortWidget::INPUT, module, Clouds::FREEZE_INPUT));
addInput(createPort<PJ301MPort>(Vec(58, 274), PortWidget::INPUT, module, Clouds::TRIG_INPUT));
addInput(createPort<PJ301MPort>(Vec(101, 274), PortWidget::INPUT, module, Clouds::POSITION_INPUT));
addInput(createPort<PJ301MPort>(Vec(144, 274), PortWidget::INPUT, module, Clouds::SIZE_INPUT));
addInput(createPort<PJ301MPort>(Vec(188, 274), PortWidget::INPUT, module, Clouds::PITCH_INPUT));
addInput(createPort<PJ301MPort>(Vec(230, 274), PortWidget::INPUT, module, Clouds::BLEND_INPUT));
addInput(createPort<PJ301MPort>(Vec(15, 317), PortWidget::INPUT, module, Clouds::IN_L_INPUT));
addInput(createPort<PJ301MPort>(Vec(58, 317), PortWidget::INPUT, module, Clouds::IN_R_INPUT));
addInput(createPort<PJ301MPort>(Vec(101, 317), PortWidget::INPUT, module, Clouds::DENSITY_INPUT));
addInput(createPort<PJ301MPort>(Vec(144, 317), PortWidget::INPUT, module, Clouds::TEXTURE_INPUT));
addOutput(createPort<PJ301MPort>(Vec(188, 317), PortWidget::OUTPUT, module, Clouds::OUT_L_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(230, 317), PortWidget::OUTPUT, module, Clouds::OUT_R_OUTPUT));
addParam(createParam<CKD6>(Vec(12, 43), module, Clouds::FREEZE_PARAM));
addParam(createParam<TL1105>(Vec(211, 50), module, Clouds::MODE_PARAM));
addParam(createParam<TL1105>(Vec(239, 50), module, Clouds::LOAD_PARAM));
addInput(createInput<PJ301MPort>(Vec(15, 274), module, Clouds::FREEZE_INPUT));
addInput(createInput<PJ301MPort>(Vec(58, 274), module, Clouds::TRIG_INPUT));
addInput(createInput<PJ301MPort>(Vec(101, 274), module, Clouds::POSITION_INPUT));
addInput(createInput<PJ301MPort>(Vec(144, 274), module, Clouds::SIZE_INPUT));
addInput(createInput<PJ301MPort>(Vec(188, 274), module, Clouds::PITCH_INPUT));
addInput(createInput<PJ301MPort>(Vec(230, 274), module, Clouds::BLEND_INPUT));
addInput(createInput<PJ301MPort>(Vec(15, 317), module, Clouds::IN_L_INPUT));
addInput(createInput<PJ301MPort>(Vec(58, 317), module, Clouds::IN_R_INPUT));
addInput(createInput<PJ301MPort>(Vec(101, 317), module, Clouds::DENSITY_INPUT));
addInput(createInput<PJ301MPort>(Vec(144, 317), module, Clouds::TEXTURE_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(188, 317), module, Clouds::OUT_L_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(230, 317), module, Clouds::OUT_R_OUTPUT));

addChild(createLight<FreezeLight>(Vec(12+3, 43+3), module, Clouds::FREEZE_LIGHT));
addChild(createLight<MediumLight<GreenRedLight>>(Vec(82.5, 53), module, Clouds::MIX_GREEN_LIGHT));


+ 116
- 85
src/Elements.cpp View File

@@ -70,17 +70,17 @@ struct Elements : Module {
NUM_LIGHTS
};

SampleRateConverter<2> inputSrc;
SampleRateConverter<2> outputSrc;
DoubleRingBuffer<Frame<2>, 256> inputBuffer;
DoubleRingBuffer<Frame<2>, 256> outputBuffer;
dsp::SampleRateConverter<2> inputSrc;
dsp::SampleRateConverter<2> outputSrc;
dsp::DoubleRingBuffer<dsp::Frame<2>, 256> inputBuffer;
dsp::DoubleRingBuffer<dsp::Frame<2>, 256> outputBuffer;

uint16_t reverb_buffer[32768] = {};
elements::Part *part;

Elements();
~Elements();
void step() override;
void process(const ProcessArgs &args) override;

json_t *dataToJson() override {
json_t *rootJ = json_object();
@@ -105,7 +105,37 @@ struct Elements : Module {
};


Elements::Elements() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
Elements::Elements() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Elements::CONTOUR_PARAM, 0.0, 1.0, 1.0);
configParam(Elements::BOW_PARAM, 0.0, 1.0, 0.0);
configParam(Elements::BLOW_PARAM, 0.0, 1.0, 0.0);
configParam(Elements::STRIKE_PARAM, 0.0, 1.0, 0.5);
configParam(Elements::COARSE_PARAM, -30.0, 30.0, 0.0);
configParam(Elements::FINE_PARAM, -2.0, 2.0, 0.0);
configParam(Elements::FM_PARAM, -1.0, 1.0, 0.0);
configParam(Elements::FLOW_PARAM, 0.0, 1.0, 0.5);
configParam(Elements::MALLET_PARAM, 0.0, 1.0, 0.5);
configParam(Elements::GEOMETRY_PARAM, 0.0, 1.0, 0.5);
configParam(Elements::BRIGHTNESS_PARAM, 0.0, 1.0, 0.5);
configParam(Elements::BOW_TIMBRE_PARAM, 0.0, 1.0, 0.5);
configParam(Elements::BLOW_TIMBRE_PARAM, 0.0, 1.0, 0.5);
configParam(Elements::STRIKE_TIMBRE_PARAM, 0.0, 1.0, 0.5);
configParam(Elements::DAMPING_PARAM, 0.0, 1.0, 0.5);
configParam(Elements::POSITION_PARAM, 0.0, 1.0, 0.5);
configParam(Elements::SPACE_PARAM, 0.0, 2.0, 0.0);
configParam(Elements::BOW_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Elements::FLOW_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Elements::BLOW_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Elements::MALLET_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Elements::STRIKE_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Elements::DAMPING_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Elements::GEOMETRY_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Elements::POSITION_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Elements::BRIGHTNESS_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Elements::SPACE_MOD_PARAM, -2.0, 2.0, 0.0);
configParam(Elements::PLAY_PARAM, 0.0, 1.0, 0.0);

part = new elements::Part();
// In the Mutable Instruments code, Part doesn't initialize itself, so zero it here.
memset(part, 0, sizeof(*part));
@@ -119,12 +149,12 @@ Elements::~Elements() {
delete part;
}

void Elements::step() {
void Elements::process(const ProcessArgs &args) {
// Get input
if (!inputBuffer.full()) {
Frame<2> inputFrame;
inputFrame.samples[0] = inputs[BLOW_INPUT].value / 5.0;
inputFrame.samples[1] = inputs[STRIKE_INPUT].value / 5.0;
dsp::Frame<2> inputFrame;
inputFrame.samples[0] = inputs[BLOW_INPUT].getVoltage() / 5.0;
inputFrame.samples[1] = inputs[STRIKE_INPUT].getVoltage() / 5.0;
inputBuffer.push(inputFrame);
}

@@ -137,8 +167,8 @@ void Elements::step() {

// Convert input buffer
{
inputSrc.setRates(engineGetSampleRate(), 32000);
Frame<2> inputFrames[16];
inputSrc.setRates(args.sampleRate, 32000);
dsp::Frame<2> inputFrames[16];
int inLen = inputBuffer.size();
int outLen = 16;
inputSrc.process(inputBuffer.startData(), &inLen, inputFrames, &outLen);
@@ -152,12 +182,12 @@ void Elements::step() {

// Set patch from parameters
elements::Patch* p = part->mutable_patch();
p->exciter_envelope_shape = params[CONTOUR_PARAM].value;
p->exciter_bow_level = params[BOW_PARAM].value;
p->exciter_blow_level = params[BLOW_PARAM].value;
p->exciter_strike_level = params[STRIKE_PARAM].value;
p->exciter_envelope_shape = params[CONTOUR_PARAM].getValue();
p->exciter_bow_level = params[BOW_PARAM].getValue();
p->exciter_blow_level = params[BLOW_PARAM].getValue();
p->exciter_strike_level = params[STRIKE_PARAM].getValue();

#define BIND(_p, _m, _i) clamp(params[_p].value + 3.3f*quadraticBipolar(params[_m].value)*inputs[_i].value/5.0f, 0.0f, 0.9995f)
#define BIND(_p, _m, _i) clamp(params[_p].getValue() + 3.3f*dsp::quadraticBipolar(params[_m].getValue())*inputs[_i].getVoltage()/5.0f, 0.0f, 0.9995f)

p->exciter_bow_timbre = BIND(BOW_TIMBRE_PARAM, BOW_TIMBRE_MOD_PARAM, BOW_TIMBRE_MOD_INPUT);
p->exciter_blow_meta = BIND(FLOW_PARAM, FLOW_MOD_PARAM, FLOW_MOD_INPUT);
@@ -168,27 +198,27 @@ void Elements::step() {
p->resonator_brightness = BIND(BRIGHTNESS_PARAM, BRIGHTNESS_MOD_PARAM, BRIGHTNESS_MOD_INPUT);
p->resonator_damping = BIND(DAMPING_PARAM, DAMPING_MOD_PARAM, DAMPING_MOD_INPUT);
p->resonator_position = BIND(POSITION_PARAM, POSITION_MOD_PARAM, POSITION_MOD_INPUT);
p->space = clamp(params[SPACE_PARAM].value + params[SPACE_MOD_PARAM].value*inputs[SPACE_MOD_INPUT].value/5.0f, 0.0f, 2.0f);
p->space = clamp(params[SPACE_PARAM].getValue() + params[SPACE_MOD_PARAM].getValue()*inputs[SPACE_MOD_INPUT].getVoltage()/5.0f, 0.0f, 2.0f);

// Get performance inputs
elements::PerformanceState performance;
performance.note = 12.0*inputs[NOTE_INPUT].value + roundf(params[COARSE_PARAM].value) + params[FINE_PARAM].value + 69.0;
performance.modulation = 3.3*quarticBipolar(params[FM_PARAM].value) * 49.5 * inputs[FM_INPUT].value/5.0;
performance.gate = params[PLAY_PARAM].value >= 1.0 || inputs[GATE_INPUT].value >= 1.0;
performance.strength = clamp(1.0 - inputs[STRENGTH_INPUT].value/5.0f, 0.0f, 1.0f);
performance.note = 12.0*inputs[NOTE_INPUT].getVoltage() + roundf(params[COARSE_PARAM].getValue()) + params[FINE_PARAM].getValue() + 69.0;
performance.modulation = 3.3*dsp::quarticBipolar(params[FM_PARAM].getValue()) * 49.5 * inputs[FM_INPUT].getVoltage()/5.0;
performance.gate = params[PLAY_PARAM].getValue() >= 1.0 || inputs[GATE_INPUT].getVoltage() >= 1.0;
performance.strength = clamp(1.0 - inputs[STRENGTH_INPUT].getVoltage()/5.0f, 0.0f, 1.0f);

// Generate audio
part->Process(performance, blow, strike, main, aux, 16);

// Convert output buffer
{
Frame<2> outputFrames[16];
dsp::Frame<2> outputFrames[16];
for (int i = 0; i < 16; i++) {
outputFrames[i].samples[0] = main[i];
outputFrames[i].samples[1] = aux[i];
}

outputSrc.setRates(32000, engineGetSampleRate());
outputSrc.setRates(32000, args.sampleRate);
int inLen = 16;
int outLen = outputBuffer.capacity();
outputSrc.process(outputFrames, &inLen, outputBuffer.endData(), &outLen);
@@ -203,9 +233,9 @@ void Elements::step() {

// Set output
if (!outputBuffer.empty()) {
Frame<2> outputFrame = outputBuffer.shift();
outputs[AUX_OUTPUT].value = 5.0 * outputFrame.samples[0];
outputs[MAIN_OUTPUT].value = 5.0 * outputFrame.samples[1];
dsp::Frame<2> outputFrame = outputBuffer.shift();
outputs[AUX_OUTPUT].setVoltage(5.0 * outputFrame.samples[0]);
outputs[MAIN_OUTPUT].setVoltage(5.0 * outputFrame.samples[1]);
}
}

@@ -224,74 +254,75 @@ struct ElementsModalItem : MenuItem {


struct ElementsWidget : ModuleWidget {
ElementsWidget(Elements *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Elements.svg")));
ElementsWidget(Elements *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Elements.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(480, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));
addChild(createWidget<ScrewSilver>(Vec(480, 365)));

addParam(createParam<Rogan1PSWhite>(Vec(28, 42), module, Elements::CONTOUR_PARAM, 0.0, 1.0, 1.0));
addParam(createParam<Rogan1PSWhite>(Vec(99, 42), module, Elements::BOW_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan1PSRed>(Vec(169, 42), module, Elements::BLOW_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan1PSGreen>(Vec(239, 42), module, Elements::STRIKE_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(Vec(310, 42), module, Elements::COARSE_PARAM, -30.0, 30.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(381, 42), module, Elements::FINE_PARAM, -2.0, 2.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(451, 42), module, Elements::FM_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Rogan3PSRed>(Vec(115, 116), module, Elements::FLOW_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan3PSGreen>(Vec(212, 116), module, Elements::MALLET_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan3PSWhite>(Vec(326, 116), module, Elements::GEOMETRY_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan3PSWhite>(Vec(423, 116), module, Elements::BRIGHTNESS_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(Vec(99, 202), module, Elements::BOW_TIMBRE_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSRed>(Vec(170, 202), module, Elements::BLOW_TIMBRE_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSGreen>(Vec(239, 202), module, Elements::STRIKE_TIMBRE_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(Vec(310, 202), module, Elements::DAMPING_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(Vec(380, 202), module, Elements::POSITION_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(Vec(451, 202), module, Elements::SPACE_PARAM, 0.0, 2.0, 0.0));
addParam(createParam<Trimpot>(Vec(104.5, 273), module, Elements::BOW_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(142.5, 273), module, Elements::FLOW_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(181.5, 273), module, Elements::BLOW_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(219.5, 273), module, Elements::MALLET_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(257.5, 273), module, Elements::STRIKE_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(315.5, 273), module, Elements::DAMPING_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(354.5, 273), module, Elements::GEOMETRY_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(392.5, 273), module, Elements::POSITION_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(430.5, 273), module, Elements::BRIGHTNESS_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(469.5, 273), module, Elements::SPACE_MOD_PARAM, -2.0, 2.0, 0.0));
addInput(createPort<PJ301MPort>(Vec(20, 178), PortWidget::INPUT, module, Elements::NOTE_INPUT));
addInput(createPort<PJ301MPort>(Vec(55, 178), PortWidget::INPUT, module, Elements::FM_INPUT));
addInput(createPort<PJ301MPort>(Vec(20, 224), PortWidget::INPUT, module, Elements::GATE_INPUT));
addInput(createPort<PJ301MPort>(Vec(55, 224), PortWidget::INPUT, module, Elements::STRENGTH_INPUT));
addInput(createPort<PJ301MPort>(Vec(20, 270), PortWidget::INPUT, module, Elements::BLOW_INPUT));
addInput(createPort<PJ301MPort>(Vec(55, 270), PortWidget::INPUT, module, Elements::STRIKE_INPUT));
addOutput(createPort<PJ301MPort>(Vec(20, 316), PortWidget::OUTPUT, module, Elements::AUX_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(55, 316), PortWidget::OUTPUT, module, Elements::MAIN_OUTPUT));
addInput(createPort<PJ301MPort>(Vec(101, 316), PortWidget::INPUT, module, Elements::BOW_TIMBRE_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(139, 316), PortWidget::INPUT, module, Elements::FLOW_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(178, 316), PortWidget::INPUT, module, Elements::BLOW_TIMBRE_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(216, 316), PortWidget::INPUT, module, Elements::MALLET_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(254, 316), PortWidget::INPUT, module, Elements::STRIKE_TIMBRE_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(312, 316), PortWidget::INPUT, module, Elements::DAMPING_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(350, 316), PortWidget::INPUT, module, Elements::GEOMETRY_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(389, 316), PortWidget::INPUT, module, Elements::POSITION_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(427, 316), PortWidget::INPUT, module, Elements::BRIGHTNESS_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(466, 316), PortWidget::INPUT, module, Elements::SPACE_MOD_INPUT));
addParam(createParam<CKD6>(Vec(36, 116), module, Elements::PLAY_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(28, 42), module, Elements::CONTOUR_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(99, 42), module, Elements::BOW_PARAM));
addParam(createParam<Rogan1PSRed>(Vec(169, 42), module, Elements::BLOW_PARAM));
addParam(createParam<Rogan1PSGreen>(Vec(239, 42), module, Elements::STRIKE_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(310, 42), module, Elements::COARSE_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(381, 42), module, Elements::FINE_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(451, 42), module, Elements::FM_PARAM));
addParam(createParam<Rogan3PSRed>(Vec(115, 116), module, Elements::FLOW_PARAM));
addParam(createParam<Rogan3PSGreen>(Vec(212, 116), module, Elements::MALLET_PARAM));
addParam(createParam<Rogan3PSWhite>(Vec(326, 116), module, Elements::GEOMETRY_PARAM));
addParam(createParam<Rogan3PSWhite>(Vec(423, 116), module, Elements::BRIGHTNESS_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(99, 202), module, Elements::BOW_TIMBRE_PARAM));
addParam(createParam<Rogan1PSRed>(Vec(170, 202), module, Elements::BLOW_TIMBRE_PARAM));
addParam(createParam<Rogan1PSGreen>(Vec(239, 202), module, Elements::STRIKE_TIMBRE_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(310, 202), module, Elements::DAMPING_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(380, 202), module, Elements::POSITION_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(451, 202), module, Elements::SPACE_PARAM));
addParam(createParam<Trimpot>(Vec(104.5, 273), module, Elements::BOW_TIMBRE_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(142.5, 273), module, Elements::FLOW_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(181.5, 273), module, Elements::BLOW_TIMBRE_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(219.5, 273), module, Elements::MALLET_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(257.5, 273), module, Elements::STRIKE_TIMBRE_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(315.5, 273), module, Elements::DAMPING_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(354.5, 273), module, Elements::GEOMETRY_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(392.5, 273), module, Elements::POSITION_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(430.5, 273), module, Elements::BRIGHTNESS_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(469.5, 273), module, Elements::SPACE_MOD_PARAM));
addInput(createInput<PJ301MPort>(Vec(20, 178), module, Elements::NOTE_INPUT));
addInput(createInput<PJ301MPort>(Vec(55, 178), module, Elements::FM_INPUT));
addInput(createInput<PJ301MPort>(Vec(20, 224), module, Elements::GATE_INPUT));
addInput(createInput<PJ301MPort>(Vec(55, 224), module, Elements::STRENGTH_INPUT));
addInput(createInput<PJ301MPort>(Vec(20, 270), module, Elements::BLOW_INPUT));
addInput(createInput<PJ301MPort>(Vec(55, 270), module, Elements::STRIKE_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(20, 316), module, Elements::AUX_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(55, 316), module, Elements::MAIN_OUTPUT));
addInput(createInput<PJ301MPort>(Vec(101, 316), module, Elements::BOW_TIMBRE_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(139, 316), module, Elements::FLOW_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(178, 316), module, Elements::BLOW_TIMBRE_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(216, 316), module, Elements::MALLET_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(254, 316), module, Elements::STRIKE_TIMBRE_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(312, 316), module, Elements::DAMPING_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(350, 316), module, Elements::GEOMETRY_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(389, 316), module, Elements::POSITION_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(427, 316), module, Elements::BRIGHTNESS_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(466, 316), module, Elements::SPACE_MOD_INPUT));
addParam(createParam<CKD6>(Vec(36, 116), module, Elements::PLAY_PARAM));

struct GateLight : YellowLight {
GateLight() {
box.size = Vec(28-6, 28-6);
bgColor = COLOR_BLACK_TRANSPARENT;
bgColor = color::BLACK_TRANSPARENT;
}
};



+ 56
- 47
src/Frames.cpp View File

@@ -46,11 +46,11 @@ struct Frames : Module {
bool poly_lfo_mode = false;
uint16_t lastControls[4] = {};

SchmittTrigger addTrigger;
SchmittTrigger delTrigger;
dsp::SchmittTrigger addTrigger;
dsp::SchmittTrigger delTrigger;

Frames();
void step() override;
void process(const ProcessArgs &args) override;

json_t *dataToJson() override {
json_t *rootJ = json_object();
@@ -130,7 +130,18 @@ struct Frames : Module {
};


Frames::Frames() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
Frames::Frames() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Frames::GAIN1_PARAM, 0.0, 1.0, 0.0);
configParam(Frames::GAIN2_PARAM, 0.0, 1.0, 0.0);
configParam(Frames::GAIN3_PARAM, 0.0, 1.0, 0.0);
configParam(Frames::GAIN4_PARAM, 0.0, 1.0, 0.0);
configParam(Frames::FRAME_PARAM, 0.0, 1.0, 0.0);
configParam(Frames::MODULATION_PARAM, -1.0, 1.0, 0.0);
configParam(Frames::ADD_PARAM, 0.0, 1.0, 0.0);
configParam(Frames::DEL_PARAM, 0.0, 1.0, 0.0);
configParam(Frames::OFFSET_PARAM, 0.0, 1.0, 0.0);

memset(&keyframer, 0, sizeof(keyframer));
keyframer.Init();
memset(&poly_lfo, 0, sizeof(poly_lfo));
@@ -140,15 +151,15 @@ Frames::Frames() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
}


void Frames::step() {
void Frames::process(const ProcessArgs &args) {
// Set gain and timestamp knobs
uint16_t controls[4];
for (int i = 0; i < 4; i++) {
controls[i] = params[GAIN1_PARAM + i].value * 65535.0;
controls[i] = params[GAIN1_PARAM + i].getValue() * 65535.0;
}

int32_t timestamp = params[FRAME_PARAM].value * 65535.0;
int32_t timestampMod = timestamp + params[MODULATION_PARAM].value * inputs[FRAME_INPUT].value / 10.0 * 65535.0;
int32_t timestamp = params[FRAME_PARAM].getValue() * 65535.0;
int32_t timestampMod = timestamp + params[MODULATION_PARAM].getValue() * inputs[FRAME_INPUT].getVoltage() / 10.0 * 65535.0;
timestamp = clamp(timestamp, 0, 65535);
timestampMod = clamp(timestampMod, 0, 65535);
int16_t nearestIndex = -1;
@@ -182,12 +193,12 @@ void Frames::step() {
}
}

if (addTrigger.process(params[ADD_PARAM].value)) {
if (addTrigger.process(params[ADD_PARAM].getValue())) {
if (nearestIndex < 0) {
keyframer.AddKeyframe(timestamp, controls);
}
}
if (delTrigger.process(params[DEL_PARAM].value)) {
if (delTrigger.process(params[DEL_PARAM].getValue())) {
if (nearestIndex >= 0) {
int32_t nearestTimestamp = keyframer.keyframe(nearestIndex).timestamp;
keyframer.RemoveKeyframe(nearestTimestamp);
@@ -221,29 +232,29 @@ void Frames::step() {
}

// Get inputs
float all = ((int)params[OFFSET_PARAM].value == 1) ? 10.0 : 0.0;
if (inputs[ALL_INPUT].active) {
all = inputs[ALL_INPUT].value;
float all = ((int)params[OFFSET_PARAM].getValue() == 1) ? 10.0 : 0.0;
if (inputs[ALL_INPUT].isConnected()) {
all = inputs[ALL_INPUT].getVoltage();
}

float ins[4];
for (int i = 0; i < 4; i++) {
ins[i] = inputs[IN1_INPUT + i].normalize(all) * gains[i];
ins[i] = inputs[IN1_INPUT + i].getNormalVoltage(all) * gains[i];
}

// Set outputs
float mix = 0.0;

for (int i = 0; i < 4; i++) {
if (outputs[OUT1_OUTPUT + i].active) {
outputs[OUT1_OUTPUT + i].value = ins[i];
if (outputs[OUT1_OUTPUT + i].isConnected()) {
outputs[OUT1_OUTPUT + i].setVoltage(ins[i]);
}
else {
mix += ins[i];
}
}

outputs[MIX_OUTPUT].value = clamp(mix / 2.0, -10.0f, 10.0f);
outputs[MIX_OUTPUT].setVoltage(clamp(mix / 2.0, -10.0f, 10.0f));

// Set lights
for (int i = 0; i < 4; i++) {
@@ -275,44 +286,45 @@ void Frames::step() {

struct CKSSRot : SVGSwitch {
CKSSRot() {
addFrame(SVG::load(assetPlugin(pluginInstance, "res/CKSS_rot_0.svg")));
addFrame(SVG::load(assetPlugin(pluginInstance, "res/CKSS_rot_1.svg")));
addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/CKSS_rot_0.svg")));
addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/CKSS_rot_1.svg")));
}
};


struct FramesWidget : ModuleWidget {
FramesWidget(Frames *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Frames.svg")));
FramesWidget(Frames *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Frames.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<Rogan1PSWhite>(Vec(14, 52), module, Frames::GAIN1_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(81, 52), module, Frames::GAIN2_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(149, 52), module, Frames::GAIN3_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(216, 52), module, Frames::GAIN4_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan6PSWhite>(Vec(89, 115), module, Frames::FRAME_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan1PSGreen>(Vec(208, 141), module, Frames::MODULATION_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<CKD6>(Vec(19, 123), module, Frames::ADD_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<CKD6>(Vec(19, 172), module, Frames::DEL_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<CKSSRot>(Vec(18, 239), module, Frames::OFFSET_PARAM, 0.0, 1.0, 0.0));
addInput(createPort<PJ301MPort>(Vec(16, 273), PortWidget::INPUT, module, Frames::ALL_INPUT));
addInput(createPort<PJ301MPort>(Vec(59, 273), PortWidget::INPUT, module, Frames::IN1_INPUT));
addInput(createPort<PJ301MPort>(Vec(102, 273), PortWidget::INPUT, module, Frames::IN2_INPUT));
addInput(createPort<PJ301MPort>(Vec(145, 273), PortWidget::INPUT, module, Frames::IN3_INPUT));
addInput(createPort<PJ301MPort>(Vec(188, 273), PortWidget::INPUT, module, Frames::IN4_INPUT));
addInput(createPort<PJ301MPort>(Vec(231, 273), PortWidget::INPUT, module, Frames::FRAME_INPUT));
addOutput(createPort<PJ301MPort>(Vec(16, 315), PortWidget::OUTPUT, module, Frames::MIX_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(59, 315), PortWidget::OUTPUT, module, Frames::OUT1_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(102, 315), PortWidget::OUTPUT, module, Frames::OUT2_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(145, 315), PortWidget::OUTPUT, module, Frames::OUT3_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(188, 315), PortWidget::OUTPUT, module, Frames::OUT4_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(231, 315), PortWidget::OUTPUT, module, Frames::FRAME_STEP_OUTPUT));
addParam(createParam<Rogan1PSWhite>(Vec(14, 52), module, Frames::GAIN1_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(81, 52), module, Frames::GAIN2_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(149, 52), module, Frames::GAIN3_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(216, 52), module, Frames::GAIN4_PARAM));
addParam(createParam<Rogan6PSWhite>(Vec(89, 115), module, Frames::FRAME_PARAM));
addParam(createParam<Rogan1PSGreen>(Vec(208, 141), module, Frames::MODULATION_PARAM));
addParam(createParam<CKD6>(Vec(19, 123), module, Frames::ADD_PARAM));
addParam(createParam<CKD6>(Vec(19, 172), module, Frames::DEL_PARAM));
addParam(createParam<CKSSRot>(Vec(18, 239), module, Frames::OFFSET_PARAM));
addInput(createInput<PJ301MPort>(Vec(16, 273), module, Frames::ALL_INPUT));
addInput(createInput<PJ301MPort>(Vec(59, 273), module, Frames::IN1_INPUT));
addInput(createInput<PJ301MPort>(Vec(102, 273), module, Frames::IN2_INPUT));
addInput(createInput<PJ301MPort>(Vec(145, 273), module, Frames::IN3_INPUT));
addInput(createInput<PJ301MPort>(Vec(188, 273), module, Frames::IN4_INPUT));
addInput(createInput<PJ301MPort>(Vec(231, 273), module, Frames::FRAME_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(16, 315), module, Frames::MIX_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(59, 315), module, Frames::OUT1_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(102, 315), module, Frames::OUT2_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(145, 315), module, Frames::OUT3_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(188, 315), module, Frames::OUT4_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(231, 315), module, Frames::FRAME_STEP_OUTPUT));

addChild(createLight<SmallLight<GreenLight>>(Vec(30, 101), module, Frames::GAIN1_LIGHT + 0));
addChild(createLight<SmallLight<GreenLight>>(Vec(97, 101), module, Frames::GAIN1_LIGHT + 1));
@@ -328,9 +340,6 @@ struct FramesWidget : ModuleWidget {
addChild(createLight<FrameLight>(Vec(100, 126), module, Frames::FRAME_LIGHT));
}




void appendContextMenu(Menu *menu) override {
Frames *frames = dynamic_cast<Frames*>(module);
assert(frames);


+ 35
- 33
src/Kinks.cpp View File

@@ -30,64 +30,66 @@ struct Kinks : Module {
NUM_LIGHTS
};

SchmittTrigger trigger;
dsp::SchmittTrigger trigger;
float sample = 0.0;

Kinks() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
void step() override;
Kinks() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);}
void process(const ProcessArgs &args) override;
};


void Kinks::step() {
void Kinks::process(const ProcessArgs &args) {
// Gaussian noise generator
float noise = 2.0 * randomNormal();
float noise = 2.0 * random::normal();

// S&H
if (trigger.process(inputs[TRIG_INPUT].value / 0.7)) {
sample = inputs[SH_INPUT].normalize(noise);
if (trigger.process(inputs[TRIG_INPUT].getVoltage() / 0.7)) {
sample = inputs[SH_INPUT].getNormalVoltage(noise);
}

// lights
lights[SIGN_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0, inputs[SIGN_INPUT].value / 5.0));
lights[SIGN_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0, -inputs[SIGN_INPUT].value / 5.0));
float logicSum = inputs[LOGIC_A_INPUT].value + inputs[LOGIC_B_INPUT].value;
lights[LOGIC_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0, logicSum / 5.0));
lights[LOGIC_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0, -logicSum / 5.0));
lights[SIGN_POS_LIGHT].setSmoothBrightness(fmaxf(0.0, inputs[SIGN_INPUT].getVoltage() / 5.0), args.sampleTime);
lights[SIGN_NEG_LIGHT].setSmoothBrightness(fmaxf(0.0, -inputs[SIGN_INPUT].getVoltage() / 5.0), args.sampleTime);
float logicSum = inputs[LOGIC_A_INPUT].getVoltage() + inputs[LOGIC_B_INPUT].getVoltage();
lights[LOGIC_POS_LIGHT].setSmoothBrightness(fmaxf(0.0, logicSum / 5.0), args.sampleTime);
lights[LOGIC_NEG_LIGHT].setSmoothBrightness(fmaxf(0.0, -logicSum / 5.0), args.sampleTime);
lights[SH_POS_LIGHT].setBrightness(fmaxf(0.0, sample / 5.0));
lights[SH_NEG_LIGHT].setBrightness(fmaxf(0.0, -sample / 5.0));

// outputs
outputs[INVERT_OUTPUT].value = -inputs[SIGN_INPUT].value;
outputs[HALF_RECTIFY_OUTPUT].value = fmaxf(0.0, inputs[SIGN_INPUT].value);
outputs[FULL_RECTIFY_OUTPUT].value = fabsf(inputs[SIGN_INPUT].value);
outputs[MAX_OUTPUT].value = fmaxf(inputs[LOGIC_A_INPUT].value, inputs[LOGIC_B_INPUT].value);
outputs[MIN_OUTPUT].value = fminf(inputs[LOGIC_A_INPUT].value, inputs[LOGIC_B_INPUT].value);
outputs[NOISE_OUTPUT].value = noise;
outputs[SH_OUTPUT].value = sample;
outputs[INVERT_OUTPUT].setVoltage(-inputs[SIGN_INPUT].getVoltage());
outputs[HALF_RECTIFY_OUTPUT].setVoltage(fmaxf(0.0, inputs[SIGN_INPUT].getVoltage()));
outputs[FULL_RECTIFY_OUTPUT].setVoltage(fabsf(inputs[SIGN_INPUT].getVoltage()));
outputs[MAX_OUTPUT].setVoltage(fmaxf(inputs[LOGIC_A_INPUT].getVoltage(), inputs[LOGIC_B_INPUT].getVoltage()));
outputs[MIN_OUTPUT].setVoltage(fminf(inputs[LOGIC_A_INPUT].getVoltage(), inputs[LOGIC_B_INPUT].getVoltage()));
outputs[NOISE_OUTPUT].setVoltage(noise);
outputs[SH_OUTPUT].setVoltage(sample);
}


struct KinksWidget : ModuleWidget {
KinksWidget(Kinks *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Kinks.svg")));
KinksWidget(Kinks *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Kinks.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));

addInput(createPort<PJ301MPort>(Vec(4, 75), PortWidget::INPUT, module, Kinks::SIGN_INPUT));
addOutput(createPort<PJ301MPort>(Vec(31, 75), PortWidget::OUTPUT, module, Kinks::INVERT_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(4, 113), PortWidget::OUTPUT, module, Kinks::HALF_RECTIFY_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(31, 113), PortWidget::OUTPUT, module, Kinks::FULL_RECTIFY_OUTPUT));
addInput(createInput<PJ301MPort>(Vec(4, 75), module, Kinks::SIGN_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(31, 75), module, Kinks::INVERT_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(4, 113), module, Kinks::HALF_RECTIFY_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(31, 113), module, Kinks::FULL_RECTIFY_OUTPUT));

addInput(createPort<PJ301MPort>(Vec(4, 177), PortWidget::INPUT, module, Kinks::LOGIC_A_INPUT));
addInput(createPort<PJ301MPort>(Vec(31, 177), PortWidget::INPUT, module, Kinks::LOGIC_B_INPUT));
addOutput(createPort<PJ301MPort>(Vec(4, 214), PortWidget::OUTPUT, module, Kinks::MAX_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(31, 214), PortWidget::OUTPUT, module, Kinks::MIN_OUTPUT));
addInput(createInput<PJ301MPort>(Vec(4, 177), module, Kinks::LOGIC_A_INPUT));
addInput(createInput<PJ301MPort>(Vec(31, 177), module, Kinks::LOGIC_B_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(4, 214), module, Kinks::MAX_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(31, 214), module, Kinks::MIN_OUTPUT));

addInput(createPort<PJ301MPort>(Vec(4, 278), PortWidget::INPUT, module, Kinks::SH_INPUT));
addInput(createPort<PJ301MPort>(Vec(31, 278), PortWidget::INPUT, module, Kinks::TRIG_INPUT));
addOutput(createPort<PJ301MPort>(Vec(4, 316), PortWidget::OUTPUT, module, Kinks::NOISE_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(31, 316), PortWidget::OUTPUT, module, Kinks::SH_OUTPUT));
addInput(createInput<PJ301MPort>(Vec(4, 278), module, Kinks::SH_INPUT));
addInput(createInput<PJ301MPort>(Vec(31, 278), module, Kinks::TRIG_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(4, 316), module, Kinks::NOISE_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(31, 316), module, Kinks::SH_OUTPUT));

addChild(createLight<SmallLight<GreenRedLight>>(Vec(11, 59), module, Kinks::SIGN_POS_LIGHT));
addChild(createLight<SmallLight<GreenRedLight>>(Vec(11, 161), module, Kinks::LOGIC_POS_LIGHT));


+ 36
- 34
src/Links.cpp View File

@@ -30,53 +30,55 @@ struct Links : Module {
NUM_LIGHTS
};

Links() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
void step() override;
Links() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);}
void process(const ProcessArgs &args) override;
};


void Links::step() {
float inA = inputs[A1_INPUT].value;
float inB = inputs[B1_INPUT].value + inputs[B2_INPUT].value;
float inC = inputs[C1_INPUT].value + inputs[C2_INPUT].value + inputs[C3_INPUT].value;
outputs[A1_OUTPUT].value = inA;
outputs[A2_OUTPUT].value = inA;
outputs[A3_OUTPUT].value = inA;
outputs[B1_OUTPUT].value = inB;
outputs[B2_OUTPUT].value = inB;
outputs[C1_OUTPUT].value = inC;
lights[A_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0, inA / 5.0));
lights[A_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0, -inA / 5.0));
lights[B_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0, inB / 5.0));
lights[B_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0, -inB / 5.0));
lights[C_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0, inC / 5.0));
lights[C_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0, -inC / 5.0));
void Links::process(const ProcessArgs &args) {
float inA = inputs[A1_INPUT].getVoltage();
float inB = inputs[B1_INPUT].getVoltage() + inputs[B2_INPUT].getVoltage();
float inC = inputs[C1_INPUT].getVoltage() + inputs[C2_INPUT].getVoltage() + inputs[C3_INPUT].getVoltage();
outputs[A1_OUTPUT].setVoltage(inA);
outputs[A2_OUTPUT].setVoltage(inA);
outputs[A3_OUTPUT].setVoltage(inA);
outputs[B1_OUTPUT].setVoltage(inB);
outputs[B2_OUTPUT].setVoltage(inB);
outputs[C1_OUTPUT].setVoltage(inC);
lights[A_POS_LIGHT].setSmoothBrightness(fmaxf(0.0, inA / 5.0), args.sampleTime);
lights[A_NEG_LIGHT].setSmoothBrightness(fmaxf(0.0, -inA / 5.0), args.sampleTime);
lights[B_POS_LIGHT].setSmoothBrightness(fmaxf(0.0, inB / 5.0), args.sampleTime);
lights[B_NEG_LIGHT].setSmoothBrightness(fmaxf(0.0, -inB / 5.0), args.sampleTime);
lights[C_POS_LIGHT].setSmoothBrightness(fmaxf(0.0, inC / 5.0), args.sampleTime);
lights[C_NEG_LIGHT].setSmoothBrightness(fmaxf(0.0, -inC / 5.0), args.sampleTime);
}


struct LinksWidget : ModuleWidget {
LinksWidget(Links *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Links.svg")));
LinksWidget(Links *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Links.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));

addInput(createPort<PJ301MPort>(Vec(4, 75), PortWidget::INPUT, module, Links::A1_INPUT));
addOutput(createPort<PJ301MPort>(Vec(31, 75), PortWidget::OUTPUT, module, Links::A1_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(4, 113), PortWidget::OUTPUT, module, Links::A2_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(31, 113), PortWidget::OUTPUT, module, Links::A3_OUTPUT));
addInput(createInput<PJ301MPort>(Vec(4, 75), module, Links::A1_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(31, 75), module, Links::A1_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(4, 113), module, Links::A2_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(31, 113), module, Links::A3_OUTPUT));

addInput(createPort<PJ301MPort>(Vec(4, 177), PortWidget::INPUT, module, Links::B1_INPUT));
addInput(createPort<PJ301MPort>(Vec(31, 177), PortWidget::INPUT, module, Links::B2_INPUT));
addOutput(createPort<PJ301MPort>(Vec(4, 214), PortWidget::OUTPUT, module, Links::B1_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(31, 214), PortWidget::OUTPUT, module, Links::B2_OUTPUT));
addInput(createInput<PJ301MPort>(Vec(4, 177), module, Links::B1_INPUT));
addInput(createInput<PJ301MPort>(Vec(31, 177), module, Links::B2_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(4, 214), module, Links::B1_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(31, 214), module, Links::B2_OUTPUT));

addInput(createPort<PJ301MPort>(Vec(4, 278), PortWidget::INPUT, module, Links::C1_INPUT));
addInput(createPort<PJ301MPort>(Vec(31, 278), PortWidget::INPUT, module, Links::C2_INPUT));
addInput(createPort<PJ301MPort>(Vec(4, 316), PortWidget::INPUT, module, Links::C3_INPUT));
addOutput(createPort<PJ301MPort>(Vec(31, 316), PortWidget::OUTPUT, module, Links::C1_OUTPUT));
addInput(createInput<PJ301MPort>(Vec(4, 278), module, Links::C1_INPUT));
addInput(createInput<PJ301MPort>(Vec(31, 278), module, Links::C2_INPUT));
addInput(createInput<PJ301MPort>(Vec(4, 316), module, Links::C3_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(31, 316), module, Links::C1_OUTPUT));

addChild(createLight<SmallLight<GreenRedLight>>(Vec(26, 59), module, Links::A_POS_LIGHT));
addChild(createLight<SmallLight<GreenRedLight>>(Vec(26, 161), module, Links::B_POS_LIGHT));


+ 84
- 66
src/Marbles.cpp View File

@@ -193,13 +193,13 @@ struct Marbles : Module {
marbles::NoteFilter note_filter;

// State
BooleanTrigger tDejaVuTrigger;
BooleanTrigger xDejaVuTrigger;
BooleanTrigger tModeTrigger;
BooleanTrigger xModeTrigger;
BooleanTrigger tRangeTrigger;
BooleanTrigger xRangeTrigger;
BooleanTrigger externalTrigger;
dsp::BooleanTrigger tDejaVuTrigger;
dsp::BooleanTrigger xDejaVuTrigger;
dsp::BooleanTrigger tModeTrigger;
dsp::BooleanTrigger xModeTrigger;
dsp::BooleanTrigger tRangeTrigger;
dsp::BooleanTrigger xRangeTrigger;
dsp::BooleanTrigger externalTrigger;
bool t_deja_vu;
bool x_deja_vu;
int t_mode;
@@ -223,7 +223,24 @@ struct Marbles : Module {
float voltages[BLOCK_SIZE * 4] = {};
int blockIndex = 0;

Marbles() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
Marbles() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Marbles::T_DEJA_VU_PARAM, 0.0, 1.0, 0.0);
configParam(Marbles::X_DEJA_VU_PARAM, 0.0, 1.0, 0.0);
configParam(Marbles::DEJA_VU_PARAM, 0.0, 1.0, 0.5);
configParam(Marbles::T_RATE_PARAM, -1.0, 1.0, 0.0);
configParam(Marbles::X_SPREAD_PARAM, 0.0, 1.0, 0.5);
configParam(Marbles::T_MODE_PARAM, 0.0, 1.0, 0.0);
configParam(Marbles::X_MODE_PARAM, 0.0, 1.0, 0.0);
configParam(Marbles::DEJA_VU_LENGTH_PARAM, 0.0, 1.0, 0.0);
configParam(Marbles::T_BIAS_PARAM, 0.0, 1.0, 0.5);
configParam(Marbles::X_BIAS_PARAM, 0.0, 1.0, 0.5);
configParam(Marbles::T_RANGE_PARAM, 0.0, 1.0, 0.0);
configParam(Marbles::X_RANGE_PARAM, 0.0, 1.0, 0.0);
configParam(Marbles::EXTERNAL_PARAM, 0.0, 1.0, 0.0);
configParam(Marbles::T_JITTER_PARAM, 0.0, 1.0, 0.0);
configParam(Marbles::X_STEPS_PARAM, 0.0, 1.0, 0.5);

random_generator.Init(1);
random_stream.Init(&random_generator);
note_filter.Init();
@@ -245,14 +262,14 @@ struct Marbles : Module {
}

void onRandomize() override {
t_mode = randomu32() % 3;
x_mode = randomu32() % 3;
t_range = randomu32() % 3;
x_range = randomu32() % 3;
t_mode = random::u32() % 3;
x_mode = random::u32() % 3;
t_range = random::u32() % 3;
x_range = random::u32() % 3;
}

void onSampleRateChange() override {
float sampleRate = engineGetSampleRate();
float sampleRate = APP->engine->getSampleRate();
t_generator.Init(&random_stream, sampleRate);
xy_generator.Init(&random_stream, sampleRate);

@@ -321,36 +338,36 @@ struct Marbles : Module {
x_clock_source_internal = json_integer_value(x_clock_source_internalJ);
}

void step() override {
void process(const ProcessArgs &args) override {
// Buttons
if (tDejaVuTrigger.process(params[T_DEJA_VU_PARAM].value <= 0.f)) {
if (tDejaVuTrigger.process(params[T_DEJA_VU_PARAM].getValue() <= 0.f)) {
t_deja_vu = !t_deja_vu;
}
if (xDejaVuTrigger.process(params[X_DEJA_VU_PARAM].value <= 0.f)) {
if (xDejaVuTrigger.process(params[X_DEJA_VU_PARAM].getValue() <= 0.f)) {
x_deja_vu = !x_deja_vu;
}
if (tModeTrigger.process(params[T_MODE_PARAM].value <= 0.f)) {
if (tModeTrigger.process(params[T_MODE_PARAM].getValue() <= 0.f)) {
t_mode = (t_mode + 1) % 3;
}
if (xModeTrigger.process(params[X_MODE_PARAM].value <= 0.f)) {
if (xModeTrigger.process(params[X_MODE_PARAM].getValue() <= 0.f)) {
x_mode = (x_mode + 1) % 3;
}
if (tRangeTrigger.process(params[T_RANGE_PARAM].value <= 0.f)) {
if (tRangeTrigger.process(params[T_RANGE_PARAM].getValue() <= 0.f)) {
t_range = (t_range + 1) % 3;
}
if (xRangeTrigger.process(params[X_RANGE_PARAM].value <= 0.f)) {
if (xRangeTrigger.process(params[X_RANGE_PARAM].getValue() <= 0.f)) {
x_range = (x_range + 1) % 3;
}
if (externalTrigger.process(params[EXTERNAL_PARAM].value <= 0.f)) {
if (externalTrigger.process(params[EXTERNAL_PARAM].getValue() <= 0.f)) {
external = !external;
}

// Clocks
bool t_gate = (inputs[T_CLOCK_INPUT].value >= 1.7f);
bool t_gate = (inputs[T_CLOCK_INPUT].getVoltage() >= 1.7f);
last_t_clock = stmlib::ExtractGateFlags(last_t_clock, t_gate);
t_clocks[blockIndex] = last_t_clock;

bool x_gate = (inputs[X_CLOCK_INPUT].value >= 1.7f);
bool x_gate = (inputs[X_CLOCK_INPUT].getVoltage() >= 1.7f);
last_xy_clock = stmlib::ExtractGateFlags(last_xy_clock, x_gate);
xy_clocks[blockIndex] = last_xy_clock;

@@ -379,21 +396,21 @@ struct Marbles : Module {

lights[EXTERNAL_LIGHT].setBrightness(external);

outputs[T1_OUTPUT].value = gates[blockIndex*2 + 0] ? 10.f : 0.f;
lights[T1_LIGHT].setBrightnessSmooth(gates[blockIndex*2 + 0]);
outputs[T2_OUTPUT].value = (ramp_master[blockIndex] < 0.5f) ? 10.f : 0.f;
lights[T2_LIGHT].setBrightnessSmooth(ramp_master[blockIndex] < 0.5f);
outputs[T3_OUTPUT].value = gates[blockIndex*2 + 1] ? 10.f : 0.f;
lights[T3_LIGHT].setBrightnessSmooth(gates[blockIndex*2 + 1]);
outputs[X1_OUTPUT].value = voltages[blockIndex*4 + 0];
lights[X1_LIGHT].setBrightnessSmooth(voltages[blockIndex*4 + 0]);
outputs[X2_OUTPUT].value = voltages[blockIndex*4 + 1];
lights[X2_LIGHT].setBrightnessSmooth(voltages[blockIndex*4 + 1]);
outputs[X3_OUTPUT].value = voltages[blockIndex*4 + 2];
lights[X3_LIGHT].setBrightnessSmooth(voltages[blockIndex*4 + 2]);
outputs[Y_OUTPUT].value = voltages[blockIndex*4 + 3];
lights[Y_LIGHT].setBrightnessSmooth(voltages[blockIndex*4 + 3]);
outputs[T1_OUTPUT].setVoltage(gates[blockIndex*2 + 0] ? 10.f : 0.f);
lights[T1_LIGHT].setSmoothBrightness(gates[blockIndex*2 + 0], args.sampleTime);
outputs[T2_OUTPUT].setVoltage((ramp_master[blockIndex] < 0.5f) ? 10.f : 0.f);
lights[T2_LIGHT].setSmoothBrightness(ramp_master[blockIndex] < 0.5f, args.sampleTime);
outputs[T3_OUTPUT].setVoltage(gates[blockIndex*2 + 1] ? 10.f : 0.f);
lights[T3_LIGHT].setSmoothBrightness(gates[blockIndex*2 + 1], args.sampleTime);
outputs[X1_OUTPUT].setVoltage(voltages[blockIndex*4 + 0]);
lights[X1_LIGHT].setSmoothBrightness(voltages[blockIndex*4 + 0], args.sampleTime);
outputs[X2_OUTPUT].setVoltage(voltages[blockIndex*4 + 1]);
lights[X2_LIGHT].setSmoothBrightness(voltages[blockIndex*4 + 1], args.sampleTime);
outputs[X3_OUTPUT].setVoltage(voltages[blockIndex*4 + 2]);
lights[X3_LIGHT].setSmoothBrightness(voltages[blockIndex*4 + 2], args.sampleTime);
outputs[Y_OUTPUT].setVoltage(voltages[blockIndex*4 + 3]);
lights[Y_LIGHT].setSmoothBrightness(voltages[blockIndex*4 + 3], args.sampleTime);
}

void stepBlock() {
@@ -405,7 +422,7 @@ struct Marbles : Module {
ramps.slave[0] = ramp_slave[0];
ramps.slave[1] = ramp_slave[1];

float deja_vu = clamp(params[DEJA_VU_PARAM].value + inputs[DEJA_VU_INPUT].value / 5.f, 0.f, 1.f);
float deja_vu = clamp(params[DEJA_VU_PARAM].getValue() + inputs[DEJA_VU_INPUT].getVoltage() / 5.f, 0.f, 1.f);
static const int loop_length[] = {
1, 1, 1, 2, 2,
2, 2, 2, 3, 3,
@@ -416,20 +433,20 @@ struct Marbles : Module {
12, 12, 14, 14, 16,
16
};
float deja_vu_length_index = params[DEJA_VU_LENGTH_PARAM].value * (LENGTHOF(loop_length) - 1);
float deja_vu_length_index = params[DEJA_VU_LENGTH_PARAM].getValue() * (LENGTHOF(loop_length) - 1);
int deja_vu_length = loop_length[(int) roundf(deja_vu_length_index)];

// Set up TGenerator

bool t_external_clock = inputs[T_CLOCK_INPUT].active;
bool t_external_clock = inputs[T_CLOCK_INPUT].isConnected();

t_generator.set_model((marbles::TGeneratorModel) t_mode);
t_generator.set_range((marbles::TGeneratorRange) t_range);
float t_rate = 60.f * (params[T_RATE_PARAM].value + inputs[T_RATE_INPUT].value / 5.f);
float t_rate = 60.f * (params[T_RATE_PARAM].getValue() + inputs[T_RATE_INPUT].getVoltage() / 5.f);
t_generator.set_rate(t_rate);
float t_bias = clamp(params[T_BIAS_PARAM].value + inputs[T_BIAS_INPUT].value / 5.f, 0.f, 1.f);
float t_bias = clamp(params[T_BIAS_PARAM].getValue() + inputs[T_BIAS_INPUT].getVoltage() / 5.f, 0.f, 1.f);
t_generator.set_bias(t_bias);
float t_jitter = clamp(params[T_JITTER_PARAM].value + inputs[T_JITTER_INPUT].value / 5.f, 0.f, 1.f);
float t_jitter = clamp(params[T_JITTER_PARAM].getValue() + inputs[T_JITTER_INPUT].getVoltage() / 5.f, 0.f, 1.f);
t_generator.set_jitter(t_jitter);
t_generator.set_deja_vu(t_deja_vu ? deja_vu : 0.f);
t_generator.set_length(deja_vu_length);
@@ -442,23 +459,23 @@ struct Marbles : Module {
// Set up XYGenerator

marbles::ClockSource x_clock_source = (marbles::ClockSource) x_clock_source_internal;
if (inputs[X_CLOCK_INPUT].active)
if (inputs[X_CLOCK_INPUT].isConnected())
x_clock_source = marbles::CLOCK_SOURCE_EXTERNAL;

marbles::GroupSettings x;
x.control_mode = (marbles::ControlMode) x_mode;
x.voltage_range = (marbles::VoltageRange) x_range;
// TODO Fix the scaling
float note_cv = 0.5f * (params[X_SPREAD_PARAM].value + inputs[X_SPREAD_INPUT].value / 5.f);
float note_cv = 0.5f * (params[X_SPREAD_PARAM].getValue() + inputs[X_SPREAD_INPUT].getVoltage() / 5.f);
float u = note_filter.Process(0.5f * (note_cv + 1.f));
x.register_mode = external;
x.register_value = u;

float x_spread = clamp(params[X_SPREAD_PARAM].value + inputs[X_SPREAD_INPUT].value / 5.f, 0.f, 1.f);
float x_spread = clamp(params[X_SPREAD_PARAM].getValue() + inputs[X_SPREAD_INPUT].getVoltage() / 5.f, 0.f, 1.f);
x.spread = x_spread;
float x_bias = clamp(params[X_BIAS_PARAM].value + inputs[X_BIAS_INPUT].value / 5.f, 0.f, 1.f);
float x_bias = clamp(params[X_BIAS_PARAM].getValue() + inputs[X_BIAS_INPUT].getVoltage() / 5.f, 0.f, 1.f);
x.bias = x_bias;
float x_steps = clamp(params[X_STEPS_PARAM].value + inputs[X_STEPS_INPUT].value / 5.f, 0.f, 1.f);
float x_steps = clamp(params[X_STEPS_PARAM].getValue() + inputs[X_STEPS_INPUT].getVoltage() / 5.f, 0.f, 1.f);
x.steps = x_steps;
x.deja_vu = x_deja_vu ? deja_vu : 0.f;
x.length = deja_vu_length;
@@ -509,29 +526,30 @@ struct CKD6Light : BASE {


struct MarblesWidget : ModuleWidget {
MarblesWidget(Marbles *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Marbles.svg")));
MarblesWidget(Marbles *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Marbles.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(createParamCentered<CKD6>(mm2px(Vec(16.545, 17.794)), module, Marbles::T_DEJA_VU_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<CKD6>(mm2px(Vec(74.845, 17.794)), module, Marbles::X_DEJA_VU_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(45.695, 22.244)), module, Marbles::DEJA_VU_PARAM, 0.0, 1.0, 0.5));
addParam(createParamCentered<Rogan3PSWhite>(mm2px(Vec(23.467, 35.264)), module, Marbles::T_RATE_PARAM, -1.0, 1.0, 0.0));
addParam(createParamCentered<Rogan3PSWhite>(mm2px(Vec(67.945, 35.243)), module, Marbles::X_SPREAD_PARAM, 0.0, 1.0, 0.5));
addParam(createParamCentered<TL1105>(mm2px(Vec(6.945, 38.794)), module, Marbles::T_MODE_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<TL1105>(mm2px(Vec(84.445, 38.793)), module, Marbles::X_MODE_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(45.695, 51.144)), module, Marbles::DEJA_VU_LENGTH_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(9.545, 58.394)), module, Marbles::T_BIAS_PARAM, 0.0, 1.0, 0.5));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(81.844, 58.394)), module, Marbles::X_BIAS_PARAM, 0.0, 1.0, 0.5));
addParam(createParamCentered<TL1105>(mm2px(Vec(26.644, 59.694)), module, Marbles::T_RANGE_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<TL1105>(mm2px(Vec(64.744, 59.694)), module, Marbles::X_RANGE_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<TL1105>(mm2px(Vec(45.694, 67.294)), module, Marbles::EXTERNAL_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(31.544, 73.694)), module, Marbles::T_JITTER_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(59.845, 73.694)), module, Marbles::X_STEPS_PARAM, 0.0, 1.0, 0.5));
addParam(createParamCentered<CKD6>(mm2px(Vec(16.545, 17.794)), module, Marbles::T_DEJA_VU_PARAM));
addParam(createParamCentered<CKD6>(mm2px(Vec(74.845, 17.794)), module, Marbles::X_DEJA_VU_PARAM));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(45.695, 22.244)), module, Marbles::DEJA_VU_PARAM));
addParam(createParamCentered<Rogan3PSWhite>(mm2px(Vec(23.467, 35.264)), module, Marbles::T_RATE_PARAM));
addParam(createParamCentered<Rogan3PSWhite>(mm2px(Vec(67.945, 35.243)), module, Marbles::X_SPREAD_PARAM));
addParam(createParamCentered<TL1105>(mm2px(Vec(6.945, 38.794)), module, Marbles::T_MODE_PARAM));
addParam(createParamCentered<TL1105>(mm2px(Vec(84.445, 38.793)), module, Marbles::X_MODE_PARAM));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(45.695, 51.144)), module, Marbles::DEJA_VU_LENGTH_PARAM));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(9.545, 58.394)), module, Marbles::T_BIAS_PARAM));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(81.844, 58.394)), module, Marbles::X_BIAS_PARAM));
addParam(createParamCentered<TL1105>(mm2px(Vec(26.644, 59.694)), module, Marbles::T_RANGE_PARAM));
addParam(createParamCentered<TL1105>(mm2px(Vec(64.744, 59.694)), module, Marbles::X_RANGE_PARAM));
addParam(createParamCentered<TL1105>(mm2px(Vec(45.694, 67.294)), module, Marbles::EXTERNAL_PARAM));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(31.544, 73.694)), module, Marbles::T_JITTER_PARAM));
addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(59.845, 73.694)), module, Marbles::X_STEPS_PARAM));

addInput(createInputCentered<PJ301MPort>(mm2px(Vec(9.545, 81.944)), module, Marbles::T_BIAS_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(81.844, 81.944)), module, Marbles::X_BIAS_INPUT));


+ 0
- 659
src/Peaks.cpp View File

@@ -1,659 +0,0 @@
#include <chrono>
#include "peaks/io_buffer.h"
#include "peaks/processors.h"
#include "AudibleInstruments.hpp"


enum SwitchIndex {
SWITCH_TWIN_MODE,
SWITCH_FUNCTION,
SWITCH_GATE_TRIG_1,
SWITCH_GATE_TRIG_2
};

enum EditMode {
EDIT_MODE_TWIN,
EDIT_MODE_SPLIT,
EDIT_MODE_FIRST,
EDIT_MODE_SECOND,
EDIT_MODE_LAST
};

enum Function {
FUNCTION_ENVELOPE,
FUNCTION_LFO,
FUNCTION_TAP_LFO,
FUNCTION_DRUM_GENERATOR,
FUNCTION_MINI_SEQUENCER,
FUNCTION_PULSE_SHAPER,
FUNCTION_PULSE_RANDOMIZER,
FUNCTION_FM_DRUM_GENERATOR,
FUNCTION_LAST,
FUNCTION_FIRST_ALTERNATE_FUNCTION = FUNCTION_MINI_SEQUENCER
};

struct Settings {
uint8_t edit_mode;
uint8_t function[2];
uint8_t pot_value[8];
bool snap_mode;
};


static const int32_t kLongPressDuration = 600;
static const uint8_t kNumAdcChannels = 4;
static const uint16_t kAdcThresholdUnlocked = 1 << (16 - 10); // 10 bits
static const uint16_t kAdcThresholdLocked = 1 << (16 - 8); // 8 bits


// Global scope, so variables can be accessed by process() function.
int16_t gOutputBuffer[peaks::kBlockSize];
int16_t gBrightness[2] = {0, 0};


static void set_led_brightness(int channel, int16_t value) {
gBrightness[channel] = value;
}

// File scope because of IOBuffer function signature.
// It cannot refer to a member function of class Peaks().
static void process(peaks::IOBuffer::Block* block, size_t size) {
for (size_t i = 0; i < peaks::kNumChannels; ++i) {
// TODO
// processors[i].Process(block->input[i], gOutputBuffer, size);
set_led_brightness(i, gOutputBuffer[0]);
for (size_t j = 0; j < size; ++j) {
// From calibration_data.h, shifting signed to unsigned values.
int32_t shifted_value = 32767 + static_cast<int32_t>(gOutputBuffer[j]);
CONSTRAIN(shifted_value, 0, 65535);
block->output[i][j] = static_cast<uint16_t>(shifted_value);
}
}
}


struct Peaks : Module {
enum ParamIds {
KNOB_1_PARAM,
KNOB_2_PARAM,
KNOB_3_PARAM,
KNOB_4_PARAM,
BUTTON_1_PARAM,
BUTTON_2_PARAM,
TRIG_1_PARAM,
TRIG_2_PARAM,
NUM_PARAMS
};
enum InputIds {
GATE_1_INPUT,
GATE_2_INPUT,
NUM_INPUTS
};
enum OutputIds {
OUT_1_OUTPUT,
OUT_2_OUTPUT,
NUM_OUTPUTS
};
enum LightIds {
TRIG_1_LIGHT,
TRIG_2_LIGHT,
TWIN_MODE_LIGHT,
FUNC_1_LIGHT,
FUNC_2_LIGHT,
FUNC_3_LIGHT,
FUNC_4_LIGHT,
NUM_LIGHTS
};

static const peaks::ProcessorFunction function_table_[FUNCTION_LAST][2];

EditMode edit_mode_ = EDIT_MODE_TWIN;
Function function_[2] = {FUNCTION_ENVELOPE, FUNCTION_ENVELOPE};
Settings settings_;

uint8_t pot_value_[8] = {0, 0, 0, 0, 0, 0, 0, 0};

bool snap_mode_ = false;
bool snapped_[4] = {false, false, false, false};

int32_t adc_lp_[kNumAdcChannels] = {0, 0, 0, 0};
int32_t adc_value_[kNumAdcChannels] = {0, 0, 0, 0};
int32_t adc_threshold_[kNumAdcChannels] = {0, 0, 0, 0};
long long press_time_[2] = {0, 0};

SchmittTrigger switches_[2];

peaks::IOBuffer ioBuffer;

peaks::GateFlags gate_flags[2] = {0, 0};

SampleRateConverter<2> outputSrc;
DoubleRingBuffer<Frame<2>, 256> outputBuffer;

bool initNumberStation = false;

peaks::Processors processors[2];

Peaks() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
settings_.edit_mode = EDIT_MODE_TWIN;
settings_.function[0] = FUNCTION_ENVELOPE;
settings_.function[1] = FUNCTION_ENVELOPE;
settings_.snap_mode = false;
std::fill(&settings_.pot_value[0], &settings_.pot_value[8], 0);

memset(&ioBuffer, 0, sizeof(ioBuffer));
memset(&processors[0], 0, sizeof(processors[0]));
memset(&processors[1], 0, sizeof(processors[1]));
ioBuffer.Init();
processors[0].Init(0);
processors[1].Init(1);
}

void onReset() override {
init();
}

void init() {
std::fill(&pot_value_[0], &pot_value_[8], 0);
std::fill(&press_time_[0], &press_time_[1], 0);
std::fill(&gBrightness[0], &gBrightness[1], 0);
std::fill(&adc_lp_[0], &adc_lp_[kNumAdcChannels], 0);
std::fill(&adc_value_[0], &adc_value_[kNumAdcChannels], 0);
std::fill(&adc_threshold_[0], &adc_threshold_[kNumAdcChannels], 0);
std::fill(&snapped_[0], &snapped_[kNumAdcChannels], false);

edit_mode_ = static_cast<EditMode>(settings_.edit_mode);
function_[0] = static_cast<Function>(settings_.function[0]);
function_[1] = static_cast<Function>(settings_.function[1]);
std::copy(&settings_.pot_value[0], &settings_.pot_value[8], &pot_value_[0]);

if (edit_mode_ == EDIT_MODE_FIRST || edit_mode_ == EDIT_MODE_SECOND) {
lockPots();
for (uint8_t i = 0; i < 4; ++i) {
processors[0].set_parameter(
i,
static_cast<uint16_t>(pot_value_[i]) << 8);
processors[1].set_parameter(
i,
static_cast<uint16_t>(pot_value_[i + 4]) << 8);
}
}

snap_mode_ = settings_.snap_mode;

changeControlMode();
setFunction(0, function_[0]);
setFunction(1, function_[1]);
}

json_t *dataToJson() override {

saveState();

json_t *rootJ = json_object();

json_object_set_new(rootJ, "edit_mode", json_integer((int)settings_.edit_mode));
json_object_set_new(rootJ, "fcn_channel_1", json_integer((int)settings_.function[0]));
json_object_set_new(rootJ, "fcn_channel_2", json_integer((int)settings_.function[1]));

json_t *potValuesJ = json_array();
for (int p : pot_value_) {
json_t *pJ = json_integer(p);
json_array_append_new(potValuesJ, pJ);
}
json_object_set_new(rootJ, "pot_values", potValuesJ);

json_object_set_new(rootJ, "snap_mode", json_boolean(settings_.snap_mode));

return rootJ;
}

void dataFromJson(json_t *rootJ) override {
json_t *editModeJ = json_object_get(rootJ, "edit_mode");
if (editModeJ) {
settings_.edit_mode = static_cast<EditMode>(json_integer_value(editModeJ));
}

json_t *fcnChannel1J = json_object_get(rootJ, "fcn_channel_1");
if (fcnChannel1J) {
settings_.function[0] = static_cast<Function>(json_integer_value(fcnChannel1J));
}

json_t *fcnChannel2J = json_object_get(rootJ, "fcn_channel_2");
if (fcnChannel2J) {
settings_.function[1] = static_cast<Function>(json_integer_value(fcnChannel2J));
}

json_t *snapModeJ = json_object_get(rootJ, "snap_mode");
if (snapModeJ) {
settings_.snap_mode = json_boolean_value(snapModeJ);
}

json_t *potValuesJ = json_object_get(rootJ, "pot_values");
size_t potValueId;
json_t *pJ;
json_array_foreach(potValuesJ, potValueId, pJ) {
if (potValueId < sizeof(pot_value_) / sizeof(pot_value_)[0]) {
settings_.pot_value[potValueId] = json_integer_value(pJ);
}
}

// Update module internal state from settings.
init();
}

void step() override {
poll();
pollPots();

// Initialize "secret" number station mode.
if (initNumberStation) {
processors[0].set_function(peaks::PROCESSOR_FUNCTION_NUMBER_STATION);
processors[1].set_function(peaks::PROCESSOR_FUNCTION_NUMBER_STATION);
initNumberStation = false;
}

if (outputBuffer.empty()) {
ioBuffer.Process(::process);

uint32_t external_gate_inputs = 0;
external_gate_inputs |= (inputs[GATE_1_INPUT].value ? 1 : 0);
external_gate_inputs |= (inputs[GATE_2_INPUT].value ? 2 : 0);

uint32_t buttons = 0;
buttons |= (params[TRIG_1_PARAM].value ? 1 : 0);
buttons |= (params[TRIG_2_PARAM].value ? 2 : 0);

uint32_t gate_inputs = external_gate_inputs | buttons;

// Prepare sample rate conversion.
// Peaks is sampling at 48kHZ.
outputSrc.setRates(48000, engineGetSampleRate());
int inLen = peaks::kBlockSize;
int outLen = outputBuffer.capacity();
Frame<2> f[peaks::kBlockSize];

// Process an entire block of data from the IOBuffer.
for (size_t k = 0; k < peaks::kBlockSize; ++k) {

peaks::IOBuffer::Slice slice = ioBuffer.NextSlice(1);

for (size_t i = 0; i < peaks::kNumChannels; ++i) {
gate_flags[i] = peaks::ExtractGateFlags(
gate_flags[i],
gate_inputs & (1 << i));

f[k].samples[i] = slice.block->output[i][slice.frame_index];
}

// A hack to make channel 1 aware of what's going on in channel 2. Used to
// reset the sequencer.
slice.block->input[0][slice.frame_index] = gate_flags[0] | (gate_flags[1] << 4) | (buttons & 8 ? peaks::GATE_FLAG_FROM_BUTTON : 0);

slice.block->input[1][slice.frame_index] = gate_flags[1] | (buttons & 2 ? peaks::GATE_FLAG_FROM_BUTTON : 0);
}

outputSrc.process(f, &inLen, outputBuffer.endData(), &outLen);
outputBuffer.endIncr(outLen);
}

// Update outputs.
if (!outputBuffer.empty()) {
Frame<2> f = outputBuffer.shift();

// Peaks manual says output spec is 0..8V for envelopes and 10Vpp for audio/CV.
// TODO Check the output values against an actual device.
outputs[OUT_1_OUTPUT].value = rescale(static_cast<float>(f.samples[0]), 0.0f, 65535.f, -8.0f, 8.0f);
outputs[OUT_2_OUTPUT].value = rescale(static_cast<float>(f.samples[1]), 0.0f, 65535.f, -8.0f, 8.0f);
}
}

inline Function function() const {
return edit_mode_ == EDIT_MODE_SECOND ? function_[1] : function_[0];
}

void changeControlMode();
void setFunction(uint8_t index, Function f);
void onPotChanged(uint16_t id, uint16_t value);
void onSwitchReleased(uint16_t id, uint16_t data);
void saveState();
void lockPots();
void poll();
void pollPots();
void refreshLeds();

long long getSystemTimeMs();
};

const peaks::ProcessorFunction Peaks::function_table_[FUNCTION_LAST][2] = {
{ peaks::PROCESSOR_FUNCTION_ENVELOPE, peaks::PROCESSOR_FUNCTION_ENVELOPE },
{ peaks::PROCESSOR_FUNCTION_LFO, peaks::PROCESSOR_FUNCTION_LFO },
{ peaks::PROCESSOR_FUNCTION_TAP_LFO, peaks::PROCESSOR_FUNCTION_TAP_LFO },
{ peaks::PROCESSOR_FUNCTION_BASS_DRUM, peaks::PROCESSOR_FUNCTION_SNARE_DRUM },

{ peaks::PROCESSOR_FUNCTION_MINI_SEQUENCER, peaks::PROCESSOR_FUNCTION_MINI_SEQUENCER },
{ peaks::PROCESSOR_FUNCTION_PULSE_SHAPER, peaks::PROCESSOR_FUNCTION_PULSE_SHAPER },
{ peaks::PROCESSOR_FUNCTION_PULSE_RANDOMIZER, peaks::PROCESSOR_FUNCTION_PULSE_RANDOMIZER },
{ peaks::PROCESSOR_FUNCTION_FM_DRUM, peaks::PROCESSOR_FUNCTION_FM_DRUM },
};


void Peaks::changeControlMode() {
uint16_t parameters[4];
for (int i = 0; i < 4; ++i) {
parameters[i] = adc_value_[i];
}

if (edit_mode_ == EDIT_MODE_SPLIT) {
processors[0].CopyParameters(&parameters[0], 2);
processors[1].CopyParameters(&parameters[2], 2);
processors[0].set_control_mode(peaks::CONTROL_MODE_HALF);
processors[1].set_control_mode(peaks::CONTROL_MODE_HALF);
}
else if (edit_mode_ == EDIT_MODE_TWIN) {
processors[0].CopyParameters(&parameters[0], 4);
processors[1].CopyParameters(&parameters[0], 4);
processors[0].set_control_mode(peaks::CONTROL_MODE_FULL);
processors[1].set_control_mode(peaks::CONTROL_MODE_FULL);
}
else {
processors[0].set_control_mode(peaks::CONTROL_MODE_FULL);
processors[1].set_control_mode(peaks::CONTROL_MODE_FULL);
}
}

void Peaks::setFunction(uint8_t index, Function f) {
if (edit_mode_ == EDIT_MODE_SPLIT || edit_mode_ == EDIT_MODE_TWIN) {
function_[0] = function_[1] = f;
processors[0].set_function(function_table_[f][0]);
processors[1].set_function(function_table_[f][1]);
}
else {
function_[index] = f;
processors[index].set_function(function_table_[f][index]);
}
}

void Peaks::onSwitchReleased(uint16_t id, uint16_t data) {
switch (id) {
case SWITCH_TWIN_MODE:
if (data > kLongPressDuration) {
edit_mode_ = static_cast<EditMode>(
(edit_mode_ + EDIT_MODE_FIRST) % EDIT_MODE_LAST);
function_[0] = function_[1];
processors[0].set_function(function_table_[function_[0]][0]);
processors[1].set_function(function_table_[function_[0]][1]);
lockPots();
}
else {
if (edit_mode_ <= EDIT_MODE_SPLIT) {
edit_mode_ = static_cast<EditMode>(EDIT_MODE_SPLIT - edit_mode_);
}
else {
edit_mode_ = static_cast<EditMode>(EDIT_MODE_SECOND - (edit_mode_ & 1));
lockPots();
}
}
changeControlMode();
saveState();
break;

case SWITCH_FUNCTION: {
Function f = function();
if (data > kLongPressDuration) {
f = static_cast<Function>((f + FUNCTION_FIRST_ALTERNATE_FUNCTION) % FUNCTION_LAST);
}
else {
if (f <= FUNCTION_DRUM_GENERATOR) {
f = static_cast<Function>((f + 1) & 3);
}
else {
f = static_cast<Function>(((f + 1) & 3) + FUNCTION_FIRST_ALTERNATE_FUNCTION);
}
}
setFunction(edit_mode_ - EDIT_MODE_FIRST, f);
saveState();
}
break;

case SWITCH_GATE_TRIG_1:
// no-op
break;

case SWITCH_GATE_TRIG_2:
// no-op
break;
}
}

void Peaks::lockPots() {
std::fill(
&adc_threshold_[0],
&adc_threshold_[kNumAdcChannels],
kAdcThresholdLocked);
std::fill(&snapped_[0], &snapped_[kNumAdcChannels], false);
}

void Peaks::pollPots() {
for (uint8_t i = 0; i < kNumAdcChannels; ++i) {
adc_lp_[i] = (int32_t(params[KNOB_1_PARAM + i].value) + adc_lp_[i] * 7) >> 3;
int32_t value = adc_lp_[i];
int32_t current_value = adc_value_[i];
if (value >= current_value + adc_threshold_[i] ||
value <= current_value - adc_threshold_[i] ||
!adc_threshold_[i]) {
onPotChanged(i, value);
adc_value_[i] = value;
adc_threshold_[i] = kAdcThresholdUnlocked;
}
}
}

void Peaks::onPotChanged(uint16_t id, uint16_t value) {
switch (edit_mode_) {
case EDIT_MODE_TWIN:
processors[0].set_parameter(id, value);
processors[1].set_parameter(id, value);
pot_value_[id] = value >> 8;
break;

case EDIT_MODE_SPLIT:
if (id < 2) {
processors[0].set_parameter(id, value);
}
else {
processors[1].set_parameter(id - 2, value);
}
pot_value_[id] = value >> 8;
break;

case EDIT_MODE_FIRST:
case EDIT_MODE_SECOND: {
uint8_t index = id + (edit_mode_ - EDIT_MODE_FIRST) * 4;
peaks::Processors* p = &processors[edit_mode_ - EDIT_MODE_FIRST];

int16_t delta = static_cast<int16_t>(pot_value_[index]) - \
static_cast<int16_t>(value >> 8);
if (delta < 0) {
delta = -delta;
}

if (!snap_mode_ || snapped_[id] || delta <= 2) {
p->set_parameter(id, value);
pot_value_[index] = value >> 8;
snapped_[id] = true;
}
}
break;

case EDIT_MODE_LAST:
break;
}
}

long long Peaks::getSystemTimeMs() {
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch()
).count();
}

void Peaks::poll() {
for (uint8_t i = 0; i < 2; ++i) {
if (switches_[i].process(params[BUTTON_1_PARAM + i].value)) {
press_time_[i] = getSystemTimeMs();
}

if (switches_[i].isHigh() && press_time_[i] != 0) {
int32_t pressed_time = getSystemTimeMs() - press_time_[i];
if (pressed_time > kLongPressDuration) {
onSwitchReleased(SWITCH_TWIN_MODE + i, pressed_time);
press_time_[i] = 0; // Inhibit next release event
}
}
if (!switches_[i].isHigh() && press_time_[i] != 0) {
int32_t delta = getSystemTimeMs() - press_time_[i] + 1;
onSwitchReleased(SWITCH_TWIN_MODE + i, delta);
press_time_[i] = 0; // Not in original code!
}
}

refreshLeds();
}

void Peaks::saveState() {
settings_.edit_mode = edit_mode_;
settings_.function[0] = function_[0];
settings_.function[1] = function_[1];
std::copy(&pot_value_[0], &pot_value_[8], &settings_.pot_value[0]);
settings_.snap_mode = snap_mode_;
}

void Peaks::refreshLeds() {
uint8_t flash = (getSystemTimeMs() >> 7) & 7;
switch (edit_mode_) {
case EDIT_MODE_FIRST:
lights[TWIN_MODE_LIGHT].value = (flash == 1) ? 1.0f : 0.0f;
break;
case EDIT_MODE_SECOND:
lights[TWIN_MODE_LIGHT].value = (flash == 1 || flash == 3) ? 1.0f : 0.0f;
break;
default:
lights[TWIN_MODE_LIGHT].value = (edit_mode_ & 1) ? 1.0f : 0.0f;
break;
}
if ((getSystemTimeMs() & 256) && function() >= FUNCTION_FIRST_ALTERNATE_FUNCTION) {
for (size_t i = 0; i < 4; ++i) {
lights[FUNC_1_LIGHT + i].value = 0.0f;
}
}
else {
for (size_t i = 0; i < 4; ++i) {
lights[FUNC_1_LIGHT + i].value = ((function() & 3) == i) ? 1.0f : 0.0f;
}
}

uint8_t b[2];
for (uint8_t i = 0; i < 2; ++i) {
switch (function_[i]) {
case FUNCTION_DRUM_GENERATOR:
case FUNCTION_FM_DRUM_GENERATOR:
b[i] = (int16_t) std::abs(gBrightness[i]) >> 8;
b[i] = b[i] >= 255 ? 255 : b[i];
break;
case FUNCTION_LFO:
case FUNCTION_TAP_LFO:
case FUNCTION_MINI_SEQUENCER: {
int32_t brightness = int32_t(gBrightness[i]) * 409 >> 8;
brightness += 32768;
brightness >>= 8;
CONSTRAIN(brightness, 0, 255);
b[i] = brightness;
}
break;
default:
b[i] = gBrightness[i] >> 7;
break;
}
}

if (processors[0].function() == peaks::PROCESSOR_FUNCTION_NUMBER_STATION) {
uint8_t pattern = processors[0].number_station().digit()
^ processors[1].number_station().digit();
for (size_t i = 0; i < 4; ++i) {
lights[FUNC_1_LIGHT + i].value = (pattern & 1) ? 1.0f : 0.0f;
pattern = pattern >> 1;
}
b[0] = processors[0].number_station().gate() ? 255 : 0;
b[1] = processors[1].number_station().gate() ? 255 : 0;
}

lights[TRIG_1_LIGHT].value = rescale(static_cast<float>(b[0]), 0.0f, 255.0f, 0.0f, 1.0f);
lights[TRIG_2_LIGHT].value = rescale(static_cast<float>(b[1]), 0.0f, 255.0f, 0.0f, 1.0f);
}


struct PeaksWidget : ModuleWidget {
PeaksWidget(Peaks *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Peaks.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));

addParam(createParam<TL1105>(Vec(8.5, 52), module, Peaks::BUTTON_1_PARAM, 0.0f, 1.0f, 0.0f));
addChild(createLight<MediumLight<GreenLight>>(Vec(11.88, 74), module, Peaks::TWIN_MODE_LIGHT));
addParam(createParam<TL1105>(Vec(8.5, 89), module, Peaks::BUTTON_2_PARAM, 0.0f, 1.0f, 0.0f));
addChild(createLight<MediumLight<GreenLight>>(Vec(11.88, 111), module, Peaks::FUNC_1_LIGHT));
addChild(createLight<MediumLight<GreenLight>>(Vec(11.88, 126.75), module, Peaks::FUNC_2_LIGHT));
addChild(createLight<MediumLight<GreenLight>>(Vec(11.88, 142.5), module, Peaks::FUNC_3_LIGHT));
addChild(createLight<MediumLight<GreenLight>>(Vec(11.88, 158), module, Peaks::FUNC_4_LIGHT));

addParam(createParam<Rogan1PSWhite>(Vec(61, 51), module, Peaks::KNOB_1_PARAM, 0.0f, 65535.0f, 16384.0f));
addParam(createParam<Rogan1PSWhite>(Vec(61, 115), module, Peaks::KNOB_2_PARAM, 0.0f, 65535.0f, 16384.0f));
addParam(createParam<Rogan1PSWhite>(Vec(61, 179), module, Peaks::KNOB_3_PARAM, 0.0f, 65535.0f, 32678.0f));
addParam(createParam<Rogan1PSWhite>(Vec(61, 244), module, Peaks::KNOB_4_PARAM, 0.0f, 65535.0f, 32678.0f));

addParam(createParam<LEDBezel>(Vec(11, 188), module, Peaks::TRIG_1_PARAM, 0.0f, 1.0f, 0.0f));
addParam(createParam<LEDBezel>(Vec(11, 273), module, Peaks::TRIG_2_PARAM, 0.0f, 1.0f, 0.0f));
addChild(createLight<LEDBezelLight<GreenLight>>(Vec(11, 188).plus(mm2px(Vec(0.75, 0.75))), module, Peaks::TRIG_1_LIGHT));
addChild(createLight<LEDBezelLight<GreenLight>>(Vec(11, 273).plus(mm2px(Vec(0.75, 0.75))), module, Peaks::TRIG_2_LIGHT));

addInput(createPort<PJ301MPort>(Vec(10, 230), PortWidget::INPUT, module, Peaks::GATE_1_INPUT));
addInput(createPort<PJ301MPort>(Vec(10, 315), PortWidget::INPUT, module, Peaks::GATE_2_INPUT));

addOutput(createPort<PJ301MPort>(Vec(53, 315), PortWidget::OUTPUT, module, Peaks::OUT_1_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(86, 315), PortWidget::OUTPUT, module, Peaks::OUT_2_OUTPUT));
}

void appendContextMenu(Menu *menu) override {
Peaks *peaks = dynamic_cast<Peaks*>(this->module);

struct SnapModeItem : MenuItem {
Peaks *peaks;
void onAction(const event::Action &e) override {
peaks->snap_mode_ = !peaks->snap_mode_;
}
void step() override {
rightText = (peaks->snap_mode_) ? "âś”" : "";
MenuItem::step();
}
};

struct NumberStationItem : MenuItem {
Peaks *peaks;
void onAction(const event::Action &e) override {
peaks->initNumberStation = true;
}
};

menu->addChild(construct<MenuLabel>());
menu->addChild(construct<SnapModeItem>(&SnapModeItem::text, "Snap Mode", &SnapModeItem::peaks, peaks));

menu->addChild(construct<MenuLabel>());
menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Secret Modes"));
menu->addChild(construct<NumberStationItem>(&NumberStationItem::text, "Number Station", &NumberStationItem::peaks, peaks));
}
};



Model *modelPeaks = createModel<Peaks, PeaksWidget>("Peaks");

+ 81
- 63
src/Plaits.cpp View File

@@ -1,5 +1,11 @@
#include "AudibleInstruments.hpp"

#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wsuggest-override"
#endif
#include "plaits/dsp/voice.h"
#pragma GCC diagnostic pop


struct Plaits : Module {
@@ -42,15 +48,26 @@ struct Plaits : Module {
char shared_buffer[16384];
float triPhase = 0.f;

SampleRateConverter<2> outputSrc;
DoubleRingBuffer<Frame<2>, 256> outputBuffer;
dsp::SampleRateConverter<2> outputSrc;
dsp::DoubleRingBuffer<dsp::Frame<2>, 256> outputBuffer;
bool lowCpu = false;
bool lpg = false;

SchmittTrigger model1Trigger;
SchmittTrigger model2Trigger;
dsp::SchmittTrigger model1Trigger;
dsp::SchmittTrigger model2Trigger;

Plaits() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Plaits::MODEL1_PARAM, 0.0, 1.0, 0.0);
configParam(Plaits::MODEL2_PARAM, 0.0, 1.0, 0.0);
configParam(Plaits::FREQ_PARAM, -4.0, 4.0, 0.0);
configParam(Plaits::HARMONICS_PARAM, 0.0, 1.0, 0.5);
configParam(Plaits::TIMBRE_PARAM, 0.0, 1.0, 0.5);
configParam(Plaits::MORPH_PARAM, 0.0, 1.0, 0.5);
configParam(Plaits::TIMBRE_CV_PARAM, -1.0, 1.0, 0.0);
configParam(Plaits::FREQ_CV_PARAM, -1.0, 1.0, 0.0);
configParam(Plaits::MORPH_CV_PARAM, -1.0, 1.0, 0.0);

Plaits() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
memset(shared_buffer, 0, sizeof(shared_buffer));
stmlib::BufferAllocator allocator(shared_buffer, sizeof(shared_buffer));
voice.Init(&allocator);
@@ -67,7 +84,7 @@ struct Plaits : Module {
}

void onRandomize() override {
patch.engine = randomu32() % 16;
patch.engine = random::u32() % 16;
}

json_t *dataToJson() override {
@@ -99,12 +116,12 @@ struct Plaits : Module {
patch.decay = json_number_value(decayJ);
}

void step() override {
void process(const ProcessArgs &args) override {
if (outputBuffer.empty()) {
const int blockSize = 12;

// Model buttons
if (model1Trigger.process(params[MODEL1_PARAM].value)) {
if (model1Trigger.process(params[MODEL1_PARAM].getValue())) {
if (patch.engine >= 8) {
patch.engine -= 8;
}
@@ -112,7 +129,7 @@ struct Plaits : Module {
patch.engine = (patch.engine + 1) % 8;
}
}
if (model2Trigger.process(params[MODEL2_PARAM].value)) {
if (model2Trigger.process(params[MODEL2_PARAM].getValue())) {
if (patch.engine < 8) {
patch.engine += 8;
}
@@ -123,7 +140,7 @@ struct Plaits : Module {

// Model lights
int activeEngine = voice.active_engine();
triPhase += 2.f * engineGetSampleTime() * blockSize;
triPhase += 2.f * args.sampleTime * blockSize;
if (triPhase >= 1.f)
triPhase -= 1.f;
float tri = (triPhase < 0.5f) ? triPhase * 2.f : (1.f - triPhase) * 2.f;
@@ -134,47 +151,47 @@ struct Plaits : Module {
}

// Calculate pitch for lowCpu mode if needed
float pitch = params[FREQ_PARAM].value;
float pitch = params[FREQ_PARAM].getValue();
if (lowCpu)
pitch += log2f(48000.f * engineGetSampleTime());
pitch += log2f(48000.f * args.sampleTime);
// Update patch
patch.note = 60.f + pitch * 12.f;
patch.harmonics = params[HARMONICS_PARAM].value;
patch.harmonics = params[HARMONICS_PARAM].getValue();
if (!lpg) {
patch.timbre = params[TIMBRE_PARAM].value;
patch.morph = params[MORPH_PARAM].value;
patch.timbre = params[TIMBRE_PARAM].getValue();
patch.morph = params[MORPH_PARAM].getValue();
}
else {
patch.lpg_colour = params[TIMBRE_PARAM].value;
patch.decay = params[MORPH_PARAM].value;
patch.lpg_colour = params[TIMBRE_PARAM].getValue();
patch.decay = params[MORPH_PARAM].getValue();
}
patch.frequency_modulation_amount = params[FREQ_CV_PARAM].value;
patch.timbre_modulation_amount = params[TIMBRE_CV_PARAM].value;
patch.morph_modulation_amount = params[MORPH_CV_PARAM].value;
patch.frequency_modulation_amount = params[FREQ_CV_PARAM].getValue();
patch.timbre_modulation_amount = params[TIMBRE_CV_PARAM].getValue();
patch.morph_modulation_amount = params[MORPH_CV_PARAM].getValue();

// Update modulations
modulations.engine = inputs[ENGINE_INPUT].value / 5.f;
modulations.note = inputs[NOTE_INPUT].value * 12.f;
modulations.frequency = inputs[FREQ_INPUT].value * 6.f;
modulations.harmonics = inputs[HARMONICS_INPUT].value / 5.f;
modulations.timbre = inputs[TIMBRE_INPUT].value / 8.f;
modulations.morph = inputs[MORPH_INPUT].value / 8.f;
modulations.engine = inputs[ENGINE_INPUT].getVoltage() / 5.f;
modulations.note = inputs[NOTE_INPUT].getVoltage() * 12.f;
modulations.frequency = inputs[FREQ_INPUT].getVoltage() * 6.f;
modulations.harmonics = inputs[HARMONICS_INPUT].getVoltage() / 5.f;
modulations.timbre = inputs[TIMBRE_INPUT].getVoltage() / 8.f;
modulations.morph = inputs[MORPH_INPUT].getVoltage() / 8.f;
// Triggers at around 0.7 V
modulations.trigger = inputs[TRIGGER_INPUT].value / 3.f;
modulations.level = inputs[LEVEL_INPUT].value / 8.f;
modulations.trigger = inputs[TRIGGER_INPUT].getVoltage() / 3.f;
modulations.level = inputs[LEVEL_INPUT].getVoltage() / 8.f;

modulations.frequency_patched = inputs[FREQ_INPUT].active;
modulations.timbre_patched = inputs[TIMBRE_INPUT].active;
modulations.morph_patched = inputs[MORPH_INPUT].active;
modulations.trigger_patched = inputs[TRIGGER_INPUT].active;
modulations.level_patched = inputs[LEVEL_INPUT].active;
modulations.frequency_patched = inputs[FREQ_INPUT].isConnected();
modulations.timbre_patched = inputs[TIMBRE_INPUT].isConnected();
modulations.morph_patched = inputs[MORPH_INPUT].isConnected();
modulations.trigger_patched = inputs[TRIGGER_INPUT].isConnected();
modulations.level_patched = inputs[LEVEL_INPUT].isConnected();

// Render frames
plaits::Voice::Frame output[blockSize];
voice.Render(patch, modulations, output, blockSize);

// Convert output to frames
Frame<2> outputFrames[blockSize];
dsp::Frame<2> outputFrames[blockSize];
for (int i = 0; i < blockSize; i++) {
outputFrames[i].samples[0] = output[i].out / 32768.f;
outputFrames[i].samples[1] = output[i].aux / 32768.f;
@@ -182,12 +199,12 @@ struct Plaits : Module {

// Convert output
if (lowCpu) {
int len = min(outputBuffer.capacity(), blockSize);
memcpy(outputBuffer.endData(), outputFrames, len * sizeof(Frame<2>));
int len = std::min((int) outputBuffer.capacity(), blockSize);
memcpy(outputBuffer.endData(), outputFrames, len * sizeof(dsp::Frame<2>));
outputBuffer.endIncr(len);
}
else {
outputSrc.setRates(48000, engineGetSampleRate());
outputSrc.setRates(48000, args.sampleRate);
int inLen = blockSize;
int outLen = outputBuffer.capacity();
outputSrc.process(outputFrames, &inLen, outputBuffer.endData(), &outLen);
@@ -197,10 +214,10 @@ struct Plaits : Module {

// Set output
if (!outputBuffer.empty()) {
Frame<2> outputFrame = outputBuffer.shift();
dsp::Frame<2> outputFrame = outputBuffer.shift();
// Inverting op-amp on outputs
outputs[OUT_OUTPUT].value = -outputFrame.samples[0] * 5.f;
outputs[AUX_OUTPUT].value = -outputFrame.samples[1] * 5.f;
outputs[OUT_OUTPUT].setVoltage(-outputFrame.samples[0] * 5.f);
outputs[AUX_OUTPUT].setVoltage(-outputFrame.samples[1] * 5.f);
}
}
};
@@ -227,35 +244,36 @@ static const std::string modelLabels[16] = {


struct PlaitsWidget : ModuleWidget {
PlaitsWidget(Plaits *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Plaits.svg")));
PlaitsWidget(Plaits *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Plaits.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<TL1105>(mm2px(Vec(23.32685, 14.6539)), module, Plaits::MODEL1_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<TL1105>(mm2px(Vec(32.22764, 14.6539)), module, Plaits::MODEL2_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan3PSWhite>(mm2px(Vec(3.1577, 20.21088)), module, Plaits::FREQ_PARAM, -4.0, 4.0, 0.0));
addParam(createParam<Rogan3PSWhite>(mm2px(Vec(39.3327, 20.21088)), module, Plaits::HARMONICS_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(mm2px(Vec(4.04171, 49.6562)), module, Plaits::TIMBRE_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(mm2px(Vec(42.71716, 49.6562)), module, Plaits::MORPH_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Trimpot>(mm2px(Vec(7.88712, 77.60705)), module, Plaits::TIMBRE_CV_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(mm2px(Vec(27.2245, 77.60705)), module, Plaits::FREQ_CV_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(mm2px(Vec(46.56189, 77.60705)), module, Plaits::MORPH_CV_PARAM, -1.0, 1.0, 0.0));
addInput(createPort<PJ301MPort>(mm2px(Vec(3.31381, 92.48067)), PortWidget::INPUT, module, Plaits::ENGINE_INPUT));
addInput(createPort<PJ301MPort>(mm2px(Vec(14.75983, 92.48067)), PortWidget::INPUT, module, Plaits::TIMBRE_INPUT));
addInput(createPort<PJ301MPort>(mm2px(Vec(26.20655, 92.48067)), PortWidget::INPUT, module, Plaits::FREQ_INPUT));
addInput(createPort<PJ301MPort>(mm2px(Vec(37.65257, 92.48067)), PortWidget::INPUT, module, Plaits::MORPH_INPUT));
addInput(createPort<PJ301MPort>(mm2px(Vec(49.0986, 92.48067)), PortWidget::INPUT, module, Plaits::HARMONICS_INPUT));
addInput(createPort<PJ301MPort>(mm2px(Vec(3.31381, 107.08103)), PortWidget::INPUT, module, Plaits::TRIGGER_INPUT));
addInput(createPort<PJ301MPort>(mm2px(Vec(14.75983, 107.08103)), PortWidget::INPUT, module, Plaits::LEVEL_INPUT));
addInput(createPort<PJ301MPort>(mm2px(Vec(26.20655, 107.08103)), PortWidget::INPUT, module, Plaits::NOTE_INPUT));
addOutput(createPort<PJ301MPort>(mm2px(Vec(37.65257, 107.08103)), PortWidget::OUTPUT, module, Plaits::OUT_OUTPUT));
addOutput(createPort<PJ301MPort>(mm2px(Vec(49.0986, 107.08103)), PortWidget::OUTPUT, module, Plaits::AUX_OUTPUT));
addParam(createParam<TL1105>(mm2px(Vec(23.32685, 14.6539)), module, Plaits::MODEL1_PARAM));
addParam(createParam<TL1105>(mm2px(Vec(32.22764, 14.6539)), module, Plaits::MODEL2_PARAM));
addParam(createParam<Rogan3PSWhite>(mm2px(Vec(3.1577, 20.21088)), module, Plaits::FREQ_PARAM));
addParam(createParam<Rogan3PSWhite>(mm2px(Vec(39.3327, 20.21088)), module, Plaits::HARMONICS_PARAM));
addParam(createParam<Rogan1PSWhite>(mm2px(Vec(4.04171, 49.6562)), module, Plaits::TIMBRE_PARAM));
addParam(createParam<Rogan1PSWhite>(mm2px(Vec(42.71716, 49.6562)), module, Plaits::MORPH_PARAM));
addParam(createParam<Trimpot>(mm2px(Vec(7.88712, 77.60705)), module, Plaits::TIMBRE_CV_PARAM));
addParam(createParam<Trimpot>(mm2px(Vec(27.2245, 77.60705)), module, Plaits::FREQ_CV_PARAM));
addParam(createParam<Trimpot>(mm2px(Vec(46.56189, 77.60705)), module, Plaits::MORPH_CV_PARAM));
addInput(createInput<PJ301MPort>(mm2px(Vec(3.31381, 92.48067)), module, Plaits::ENGINE_INPUT));
addInput(createInput<PJ301MPort>(mm2px(Vec(14.75983, 92.48067)), module, Plaits::TIMBRE_INPUT));
addInput(createInput<PJ301MPort>(mm2px(Vec(26.20655, 92.48067)), module, Plaits::FREQ_INPUT));
addInput(createInput<PJ301MPort>(mm2px(Vec(37.65257, 92.48067)), module, Plaits::MORPH_INPUT));
addInput(createInput<PJ301MPort>(mm2px(Vec(49.0986, 92.48067)), module, Plaits::HARMONICS_INPUT));
addInput(createInput<PJ301MPort>(mm2px(Vec(3.31381, 107.08103)), module, Plaits::TRIGGER_INPUT));
addInput(createInput<PJ301MPort>(mm2px(Vec(14.75983, 107.08103)), module, Plaits::LEVEL_INPUT));
addInput(createInput<PJ301MPort>(mm2px(Vec(26.20655, 107.08103)), module, Plaits::NOTE_INPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(37.65257, 107.08103)), module, Plaits::OUT_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(49.0986, 107.08103)), module, Plaits::AUX_OUTPUT));

addChild(createLight<MediumLight<GreenRedLight>>(mm2px(Vec(28.79498, 23.31649)), module, Plaits::MODEL_LIGHT + 0 * 2));
addChild(createLight<MediumLight<GreenRedLight>>(mm2px(Vec(28.79498, 28.71704)), module, Plaits::MODEL_LIGHT + 1 * 2));


+ 81
- 66
src/Rings.cpp View File

@@ -45,10 +45,10 @@ struct Rings : Module {
NUM_LIGHTS
};

SampleRateConverter<1> inputSrc;
SampleRateConverter<2> outputSrc;
DoubleRingBuffer<Frame<1>, 256> inputBuffer;
DoubleRingBuffer<Frame<2>, 256> outputBuffer;
dsp::SampleRateConverter<1> inputSrc;
dsp::SampleRateConverter<2> outputSrc;
dsp::DoubleRingBuffer<dsp::Frame<1>, 256> inputBuffer;
dsp::DoubleRingBuffer<dsp::Frame<2>, 256> outputBuffer;

uint16_t reverb_buffer[32768] = {};
rings::Part part;
@@ -57,14 +57,14 @@ struct Rings : Module {
bool strum = false;
bool lastStrum = false;

SchmittTrigger polyphonyTrigger;
SchmittTrigger modelTrigger;
dsp::SchmittTrigger polyphonyTrigger;
dsp::SchmittTrigger modelTrigger;
int polyphonyMode = 0;
rings::ResonatorModel resonatorModel = rings::RESONATOR_MODEL_MODAL;
bool easterEgg = false;

Rings();
void step() override;
void process(const ProcessArgs &args) override;

json_t *dataToJson() override {
json_t *rootJ = json_object();
@@ -99,13 +99,27 @@ struct Rings : Module {
}

void onRandomize() override {
polyphonyMode = randomu32() % 3;
resonatorModel = (rings::ResonatorModel) (randomu32() % 3);
polyphonyMode = random::u32() % 3;
resonatorModel = (rings::ResonatorModel) (random::u32() % 3);
}
};


Rings::Rings() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
Rings::Rings() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Rings::POLYPHONY_PARAM, 0.0, 1.0, 0.0);
configParam(Rings::RESONATOR_PARAM, 0.0, 1.0, 0.0);
configParam(Rings::FREQUENCY_PARAM, 0.0, 60.0, 30.0);
configParam(Rings::STRUCTURE_PARAM, 0.0, 1.0, 0.5);
configParam(Rings::BRIGHTNESS_PARAM, 0.0, 1.0, 0.5);
configParam(Rings::DAMPING_PARAM, 0.0, 1.0, 0.5);
configParam(Rings::POSITION_PARAM, 0.0, 1.0, 0.5);
configParam(Rings::BRIGHTNESS_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Rings::FREQUENCY_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Rings::DAMPING_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Rings::STRUCTURE_MOD_PARAM, -1.0, 1.0, 0.0);
configParam(Rings::POSITION_MOD_PARAM, -1.0, 1.0, 0.0);

memset(&strummer, 0, sizeof(strummer));
memset(&part, 0, sizeof(part));
memset(&string_synth, 0, sizeof(string_synth));
@@ -115,28 +129,28 @@ Rings::Rings() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
string_synth.Init(reverb_buffer);
}

void Rings::step() {
void Rings::process(const ProcessArgs &args) {
// TODO
// "Normalized to a pulse/burst generator that reacts to note changes on the V/OCT input."
// Get input
if (!inputBuffer.full()) {
Frame<1> f;
f.samples[0] = inputs[IN_INPUT].value / 5.0;
dsp::Frame<1> f;
f.samples[0] = inputs[IN_INPUT].getVoltage() / 5.0;
inputBuffer.push(f);
}

if (!strum) {
strum = inputs[STRUM_INPUT].value >= 1.0;
strum = inputs[STRUM_INPUT].getVoltage() >= 1.0;
}

// Polyphony / model
if (polyphonyTrigger.process(params[POLYPHONY_PARAM].value)) {
if (polyphonyTrigger.process(params[POLYPHONY_PARAM].getValue())) {
polyphonyMode = (polyphonyMode + 1) % 3;
}
lights[POLYPHONY_GREEN_LIGHT].value = (polyphonyMode == 0 || polyphonyMode == 1) ? 1.0 : 0.0;
lights[POLYPHONY_RED_LIGHT].value = (polyphonyMode == 1 || polyphonyMode == 2) ? 1.0 : 0.0;

if (modelTrigger.process(params[RESONATOR_PARAM].value)) {
if (modelTrigger.process(params[RESONATOR_PARAM].getValue())) {
resonatorModel = (rings::ResonatorModel) ((resonatorModel + 1) % 3);
}
int modelColor = resonatorModel % 3;
@@ -148,10 +162,10 @@ void Rings::step() {
float in[24] = {};
// Convert input buffer
{
inputSrc.setRates(engineGetSampleRate(), 48000);
inputSrc.setRates(args.sampleRate, 48000);
int inLen = inputBuffer.size();
int outLen = 24;
inputSrc.process(inputBuffer.startData(), &inLen, (Frame<1>*) in, &outLen);
inputSrc.process(inputBuffer.startData(), &inLen, (dsp::Frame<1>*) in, &outLen);
inputBuffer.startIncr(inLen);
}

@@ -167,26 +181,26 @@ void Rings::step() {

// Patch
rings::Patch patch;
float structure = params[STRUCTURE_PARAM].value + 3.3*quadraticBipolar(params[STRUCTURE_MOD_PARAM].value)*inputs[STRUCTURE_MOD_INPUT].value/5.0;
float structure = params[STRUCTURE_PARAM].getValue() + 3.3*dsp::quadraticBipolar(params[STRUCTURE_MOD_PARAM].getValue())*inputs[STRUCTURE_MOD_INPUT].getVoltage()/5.0;
patch.structure = clamp(structure, 0.0f, 0.9995f);
patch.brightness = clamp(params[BRIGHTNESS_PARAM].value + 3.3*quadraticBipolar(params[BRIGHTNESS_MOD_PARAM].value)*inputs[BRIGHTNESS_MOD_INPUT].value/5.0, 0.0f, 1.0f);
patch.damping = clamp(params[DAMPING_PARAM].value + 3.3*quadraticBipolar(params[DAMPING_MOD_PARAM].value)*inputs[DAMPING_MOD_INPUT].value/5.0, 0.0f, 0.9995f);
patch.position = clamp(params[POSITION_PARAM].value + 3.3*quadraticBipolar(params[POSITION_MOD_PARAM].value)*inputs[POSITION_MOD_INPUT].value/5.0, 0.0f, 0.9995f);
patch.brightness = clamp(params[BRIGHTNESS_PARAM].getValue() + 3.3*dsp::quadraticBipolar(params[BRIGHTNESS_MOD_PARAM].getValue())*inputs[BRIGHTNESS_MOD_INPUT].getVoltage()/5.0, 0.0f, 1.0f);
patch.damping = clamp(params[DAMPING_PARAM].getValue() + 3.3*dsp::quadraticBipolar(params[DAMPING_MOD_PARAM].getValue())*inputs[DAMPING_MOD_INPUT].getVoltage()/5.0, 0.0f, 0.9995f);
patch.position = clamp(params[POSITION_PARAM].getValue() + 3.3*dsp::quadraticBipolar(params[POSITION_MOD_PARAM].getValue())*inputs[POSITION_MOD_INPUT].getVoltage()/5.0, 0.0f, 0.9995f);

// Performance
rings::PerformanceState performance_state;
performance_state.note = 12.0*inputs[PITCH_INPUT].normalize(1/12.0);
float transpose = params[FREQUENCY_PARAM].value;
performance_state.note = 12.0*inputs[PITCH_INPUT].getNormalVoltage(1/12.0);
float transpose = params[FREQUENCY_PARAM].getValue();
// Quantize transpose if pitch input is connected
if (inputs[PITCH_INPUT].active) {
if (inputs[PITCH_INPUT].isConnected()) {
transpose = roundf(transpose);
}
performance_state.tonic = 12.0 + clamp(transpose, 0.0f, 60.0f);
performance_state.fm = clamp(48.0 * 3.3*quarticBipolar(params[FREQUENCY_MOD_PARAM].value) * inputs[FREQUENCY_MOD_INPUT].normalize(1.0)/5.0, -48.0f, 48.0f);
performance_state.fm = clamp(48.0 * 3.3*dsp::quarticBipolar(params[FREQUENCY_MOD_PARAM].getValue()) * inputs[FREQUENCY_MOD_INPUT].getNormalVoltage(1.0)/5.0, -48.0f, 48.0f);

performance_state.internal_exciter = !inputs[IN_INPUT].active;
performance_state.internal_strum = !inputs[STRUM_INPUT].active;
performance_state.internal_note = !inputs[PITCH_INPUT].active;
performance_state.internal_exciter = !inputs[IN_INPUT].isConnected();
performance_state.internal_strum = !inputs[STRUM_INPUT].isConnected();
performance_state.internal_note = !inputs[PITCH_INPUT].isConnected();

// TODO
// "Normalized to a step detector on the V/OCT input and a transient detector on the IN input."
@@ -210,13 +224,13 @@ void Rings::step() {

// Convert output buffer
{
Frame<2> outputFrames[24];
dsp::Frame<2> outputFrames[24];
for (int i = 0; i < 24; i++) {
outputFrames[i].samples[0] = out[i];
outputFrames[i].samples[1] = aux[i];
}

outputSrc.setRates(48000, engineGetSampleRate());
outputSrc.setRates(48000, args.sampleRate);
int inLen = 24;
int outLen = outputBuffer.capacity();
outputSrc.process(outputFrames, &inLen, outputBuffer.endData(), &outLen);
@@ -226,57 +240,58 @@ void Rings::step() {

// Set output
if (!outputBuffer.empty()) {
Frame<2> outputFrame = outputBuffer.shift();
dsp::Frame<2> outputFrame = outputBuffer.shift();
// "Note that you need to insert a jack into each output to split the signals: when only one jack is inserted, both signals are mixed together."
if (outputs[ODD_OUTPUT].active && outputs[EVEN_OUTPUT].active) {
outputs[ODD_OUTPUT].value = clamp(outputFrame.samples[0], -1.0, 1.0)*5.0;
outputs[EVEN_OUTPUT].value = clamp(outputFrame.samples[1], -1.0, 1.0)*5.0;
if (outputs[ODD_OUTPUT].isConnected() && outputs[EVEN_OUTPUT].isConnected()) {
outputs[ODD_OUTPUT].setVoltage(clamp(outputFrame.samples[0], -1.0, 1.0)*5.0);
outputs[EVEN_OUTPUT].setVoltage(clamp(outputFrame.samples[1], -1.0, 1.0)*5.0);
}
else {
float v = clamp(outputFrame.samples[0] + outputFrame.samples[1], -1.0, 1.0)*5.0;
outputs[ODD_OUTPUT].value = v;
outputs[EVEN_OUTPUT].value = v;
outputs[ODD_OUTPUT].setVoltage(v);
outputs[EVEN_OUTPUT].setVoltage(v);
}
}
}


struct RingsWidget : ModuleWidget {
RingsWidget(Rings *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Rings.svg")));
RingsWidget(Rings *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Rings.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(180, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));
addChild(createWidget<ScrewSilver>(Vec(180, 365)));

addParam(createParam<TL1105>(Vec(14, 40), module, Rings::POLYPHONY_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<TL1105>(Vec(179, 40), module, Rings::RESONATOR_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan3PSWhite>(Vec(29, 72), module, Rings::FREQUENCY_PARAM, 0.0, 60.0, 30.0));
addParam(createParam<Rogan3PSWhite>(Vec(126, 72), module, Rings::STRUCTURE_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(Vec(13, 158), module, Rings::BRIGHTNESS_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(Vec(83, 158), module, Rings::DAMPING_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(Vec(154, 158), module, Rings::POSITION_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Trimpot>(Vec(19, 229), module, Rings::BRIGHTNESS_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(57, 229), module, Rings::FREQUENCY_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(96, 229), module, Rings::DAMPING_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(134, 229), module, Rings::STRUCTURE_MOD_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(173, 229), module, Rings::POSITION_MOD_PARAM, -1.0, 1.0, 0.0));
addInput(createPort<PJ301MPort>(Vec(15, 273), PortWidget::INPUT, module, Rings::BRIGHTNESS_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(54, 273), PortWidget::INPUT, module, Rings::FREQUENCY_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(92, 273), PortWidget::INPUT, module, Rings::DAMPING_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(131, 273), PortWidget::INPUT, module, Rings::STRUCTURE_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(169, 273), PortWidget::INPUT, module, Rings::POSITION_MOD_INPUT));
addInput(createPort<PJ301MPort>(Vec(15, 316), PortWidget::INPUT, module, Rings::STRUM_INPUT));
addInput(createPort<PJ301MPort>(Vec(54, 316), PortWidget::INPUT, module, Rings::PITCH_INPUT));
addInput(createPort<PJ301MPort>(Vec(92, 316), PortWidget::INPUT, module, Rings::IN_INPUT));
addOutput(createPort<PJ301MPort>(Vec(131, 316), PortWidget::OUTPUT, module, Rings::ODD_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(169, 316), PortWidget::OUTPUT, module, Rings::EVEN_OUTPUT));
addParam(createParam<TL1105>(Vec(14, 40), module, Rings::POLYPHONY_PARAM));
addParam(createParam<TL1105>(Vec(179, 40), module, Rings::RESONATOR_PARAM));
addParam(createParam<Rogan3PSWhite>(Vec(29, 72), module, Rings::FREQUENCY_PARAM));
addParam(createParam<Rogan3PSWhite>(Vec(126, 72), module, Rings::STRUCTURE_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(13, 158), module, Rings::BRIGHTNESS_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(83, 158), module, Rings::DAMPING_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(154, 158), module, Rings::POSITION_PARAM));
addParam(createParam<Trimpot>(Vec(19, 229), module, Rings::BRIGHTNESS_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(57, 229), module, Rings::FREQUENCY_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(96, 229), module, Rings::DAMPING_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(134, 229), module, Rings::STRUCTURE_MOD_PARAM));
addParam(createParam<Trimpot>(Vec(173, 229), module, Rings::POSITION_MOD_PARAM));
addInput(createInput<PJ301MPort>(Vec(15, 273), module, Rings::BRIGHTNESS_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(54, 273), module, Rings::FREQUENCY_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(92, 273), module, Rings::DAMPING_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(131, 273), module, Rings::STRUCTURE_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(169, 273), module, Rings::POSITION_MOD_INPUT));
addInput(createInput<PJ301MPort>(Vec(15, 316), module, Rings::STRUM_INPUT));
addInput(createInput<PJ301MPort>(Vec(54, 316), module, Rings::PITCH_INPUT));
addInput(createInput<PJ301MPort>(Vec(92, 316), module, Rings::IN_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(131, 316), module, Rings::ODD_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(169, 316), module, Rings::EVEN_OUTPUT));

addChild(createLight<MediumLight<GreenRedLight>>(Vec(37, 43), module, Rings::POLYPHONY_GREEN_LIGHT));
addChild(createLight<MediumLight<GreenRedLight>>(Vec(162, 43), module, Rings::RESONATOR_GREEN_LIGHT));


+ 31
- 22
src/Shades.cpp View File

@@ -30,29 +30,37 @@ struct Shades : Module {
NUM_LIGHTS
};

Shades() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
void step() override;
Shades() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Shades::GAIN1_PARAM, 0.0, 1.0, 0.5);
configParam(Shades::GAIN2_PARAM, 0.0, 1.0, 0.5);
configParam(Shades::GAIN3_PARAM, 0.0, 1.0, 0.5);
configParam(Shades::MODE1_PARAM, 0.0, 1.0, 1.0);
configParam(Shades::MODE2_PARAM, 0.0, 1.0, 1.0);
configParam(Shades::MODE3_PARAM, 0.0, 1.0, 1.0);
}
void process(const ProcessArgs &args) override;
};


void Shades::step() {
void Shades::process(const ProcessArgs &args) {
float out = 0.0;

for (int i = 0; i < 3; i++) {
float in = inputs[IN1_INPUT + i].normalize(5.0);
if ((int)params[MODE1_PARAM + i].value == 1) {
if ((int)params[MODE1_PARAM + i].getValue() == 1) {
// attenuverter
in *= 2.0 * params[GAIN1_PARAM + i].value - 1.0;
in *= 2.0 * params[GAIN1_PARAM + i].getValue() - 1.0;
}
else {
// attenuator
in *= params[GAIN1_PARAM + i].value;
in *= params[GAIN1_PARAM + i].getValue();
}
out += in;
lights[OUT1_POS_LIGHT + 2*i].setBrightnessSmooth(fmaxf(0.0, out / 5.0));
lights[OUT1_NEG_LIGHT + 2*i].setBrightnessSmooth(fmaxf(0.0, -out / 5.0));
if (outputs[OUT1_OUTPUT + i].active) {
outputs[OUT1_OUTPUT + i].value = out;
if (outputs[OUT1_OUTPUT + i].isConnected()) {
outputs[OUT1_OUTPUT + i].setVoltage(out);
out = 0.0;
}
}
@@ -60,27 +68,28 @@ void Shades::step() {


struct ShadesWidget : ModuleWidget {
ShadesWidget(Shades *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Shades.svg")));
ShadesWidget(Shades *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Shades.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));

addParam(createParam<Rogan1PSRed>(Vec(40, 40), module, Shades::GAIN1_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSWhite>(Vec(40, 106), module, Shades::GAIN2_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSGreen>(Vec(40, 172), module, Shades::GAIN3_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<Rogan1PSRed>(Vec(40, 40), module, Shades::GAIN1_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(40, 106), module, Shades::GAIN2_PARAM));
addParam(createParam<Rogan1PSGreen>(Vec(40, 172), module, Shades::GAIN3_PARAM));

addParam(createParam<CKSS>(Vec(10, 51), module, Shades::MODE1_PARAM, 0.0, 1.0, 1.0));
addParam(createParam<CKSS>(Vec(10, 117), module, Shades::MODE2_PARAM, 0.0, 1.0, 1.0));
addParam(createParam<CKSS>(Vec(10, 183), module, Shades::MODE3_PARAM, 0.0, 1.0, 1.0));
addParam(createParam<CKSS>(Vec(10, 51), module, Shades::MODE1_PARAM));
addParam(createParam<CKSS>(Vec(10, 117), module, Shades::MODE2_PARAM));
addParam(createParam<CKSS>(Vec(10, 183), module, Shades::MODE3_PARAM));

addInput(createPort<PJ301MPort>(Vec(9, 245), PortWidget::INPUT, module, Shades::IN1_INPUT));
addInput(createPort<PJ301MPort>(Vec(9, 281), PortWidget::INPUT, module, Shades::IN2_INPUT));
addInput(createPort<PJ301MPort>(Vec(9, 317), PortWidget::INPUT, module, Shades::IN3_INPUT));
addInput(createInput<PJ301MPort>(Vec(9, 245), module, Shades::IN1_INPUT));
addInput(createInput<PJ301MPort>(Vec(9, 281), module, Shades::IN2_INPUT));
addInput(createInput<PJ301MPort>(Vec(9, 317), module, Shades::IN3_INPUT));

addOutput(createPort<PJ301MPort>(Vec(56, 245), PortWidget::OUTPUT, module, Shades::OUT1_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(56, 281), PortWidget::OUTPUT, module, Shades::OUT2_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(56, 317), PortWidget::OUTPUT, module, Shades::OUT3_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(56, 245), module, Shades::OUT1_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(56, 281), module, Shades::OUT2_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(56, 317), module, Shades::OUT3_OUTPUT));

addChild(createLight<SmallLight<GreenRedLight>>(Vec(41, 254), module, Shades::OUT1_POS_LIGHT));
addChild(createLight<SmallLight<GreenRedLight>>(Vec(41, 290), module, Shades::OUT2_POS_LIGHT));


+ 72
- 51
src/Stages.cpp View File

@@ -15,14 +15,14 @@ struct LongPressButton {
};

float pressedTime = 0.f;
BooleanTrigger trigger;
dsp::BooleanTrigger trigger;

Events step(Param &param) {
Events result = NO_PRESS;

bool pressed = param.value > 0.f;
if (pressed && pressedTime >= 0.f) {
pressedTime += engineGetSampleTime();
pressedTime += APP->engine->getSampleTime();
if (pressedTime >= 1.f) {
pressedTime = -1.f;
result = LONG_PRESS;
@@ -153,7 +153,27 @@ struct Stages : Module {
int blockIndex = 0;
GroupBuilder groupBuilder;

Stages() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
Stages() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Stages::SHAPE_PARAMS + 0, 0.0, 1.0, 0.5);
configParam(Stages::SHAPE_PARAMS + 1, 0.0, 1.0, 0.5);
configParam(Stages::SHAPE_PARAMS + 2, 0.0, 1.0, 0.5);
configParam(Stages::SHAPE_PARAMS + 3, 0.0, 1.0, 0.5);
configParam(Stages::SHAPE_PARAMS + 4, 0.0, 1.0, 0.5);
configParam(Stages::SHAPE_PARAMS + 5, 0.0, 1.0, 0.5);
configParam(Stages::TYPE_PARAMS + 0, 0.0, 1.0, 0.0);
configParam(Stages::TYPE_PARAMS + 1, 0.0, 1.0, 0.0);
configParam(Stages::TYPE_PARAMS + 2, 0.0, 1.0, 0.0);
configParam(Stages::TYPE_PARAMS + 3, 0.0, 1.0, 0.0);
configParam(Stages::TYPE_PARAMS + 4, 0.0, 1.0, 0.0);
configParam(Stages::TYPE_PARAMS + 5, 0.0, 1.0, 0.0);
configParam(Stages::LEVEL_PARAMS + 0, 0.0, 1.0, 0.5);
configParam(Stages::LEVEL_PARAMS + 1, 0.0, 1.0, 0.5);
configParam(Stages::LEVEL_PARAMS + 2, 0.0, 1.0, 0.5);
configParam(Stages::LEVEL_PARAMS + 3, 0.0, 1.0, 0.5);
configParam(Stages::LEVEL_PARAMS + 4, 0.0, 1.0, 0.5);
configParam(Stages::LEVEL_PARAMS + 5, 0.0, 1.0, 0.5);

onReset();
}

@@ -203,7 +223,7 @@ struct Stages : Module {

void onSampleRateChange() override {
for (int i = 0; i < NUM_CHANNELS; i++) {
segment_generator[i].SetSampleRate(engineGetSampleRate());
segment_generator[i].SetSampleRate(APP->engine->getSampleRate());
}
}

@@ -212,8 +232,8 @@ struct Stages : Module {
float primaries[NUM_CHANNELS];
float secondaries[NUM_CHANNELS];
for (int i = 0; i < NUM_CHANNELS; i++) {
primaries[i] = clamp(params[LEVEL_PARAMS + i].value + inputs[LEVEL_INPUTS + i].value / 8.f, 0.f, 1.f);
secondaries[i] = params[SHAPE_PARAMS + i].value;
primaries[i] = clamp(params[LEVEL_PARAMS + i].getValue() + inputs[LEVEL_INPUTS + i].getVoltage() / 8.f, 0.f, 1.f);
secondaries[i] = params[SHAPE_PARAMS + i].getValue();
}

// See if the group associations have changed since the last group
@@ -309,9 +329,9 @@ struct Stages : Module {
}
}

void step() override {
void process(const ProcessArgs &args) override {
// Oscillate flashing the type lights
lightOscillatorPhase += 0.5f * engineGetSampleTime();
lightOscillatorPhase += 0.5f * args.sampleTime;
if (lightOscillatorPhase >= 1.0f)
lightOscillatorPhase -= 1.0f;

@@ -327,7 +347,7 @@ struct Stages : Module {

// Input
for (int i = 0; i < NUM_CHANNELS; i++) {
bool gate = (inputs[GATE_INPUTS + i].value >= 1.7f);
bool gate = (inputs[GATE_INPUTS + i].getVoltage() >= 1.7f);
last_gate_flags[i] = stmlib::ExtractGateFlags(last_gate_flags[i], gate);
gate_flags[i][blockIndex] = last_gate_flags[i];
}
@@ -347,8 +367,8 @@ struct Stages : Module {
int segment = group.first_segment + j;

float envelope = envelopeBuffer[segment][blockIndex];
outputs[ENVELOPE_OUTPUTS + segment].value = envelope * 8.f;
lights[ENVELOPE_LIGHTS + segment].setBrightnessSmooth(envelope);
outputs[ENVELOPE_OUTPUTS + segment].setVoltage(envelope * 8.f);
lights[ENVELOPE_LIGHTS + segment].setSmoothBrightness(envelope, args.sampleTime);

numberOfLoopsInGroup += configurations[segment].loop ? 1 : 0;
float flashlevel = 1.f;
@@ -373,52 +393,53 @@ struct Stages : Module {


struct StagesWidget : ModuleWidget {
StagesWidget(Stages *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Stages.svg")));
StagesWidget(Stages *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Stages.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<Trimpot>(mm2px(Vec(3.72965, 13.98158)), module, Stages::SHAPE_PARAMS + 0, 0.0, 1.0, 0.5));
addParam(createParam<Trimpot>(mm2px(Vec(15.17012, 13.98158)), module, Stages::SHAPE_PARAMS + 1, 0.0, 1.0, 0.5));
addParam(createParam<Trimpot>(mm2px(Vec(26.6099, 13.98158)), module, Stages::SHAPE_PARAMS + 2, 0.0, 1.0, 0.5));
addParam(createParam<Trimpot>(mm2px(Vec(38.07174, 13.98158)), module, Stages::SHAPE_PARAMS + 3, 0.0, 1.0, 0.5));
addParam(createParam<Trimpot>(mm2px(Vec(49.51152, 13.98158)), module, Stages::SHAPE_PARAMS + 4, 0.0, 1.0, 0.5));
addParam(createParam<Trimpot>(mm2px(Vec(60.95199, 13.98158)), module, Stages::SHAPE_PARAMS + 5, 0.0, 1.0, 0.5));
addParam(createParam<TL1105>(mm2px(Vec(4.17259, 32.37248)), module, Stages::TYPE_PARAMS + 0, 0.0, 1.0, 0.0));
addParam(createParam<TL1105>(mm2px(Vec(15.61237, 32.37248)), module, Stages::TYPE_PARAMS + 1, 0.0, 1.0, 0.0));
addParam(createParam<TL1105>(mm2px(Vec(27.05284, 32.37248)), module, Stages::TYPE_PARAMS + 2, 0.0, 1.0, 0.0));
addParam(createParam<TL1105>(mm2px(Vec(38.51399, 32.37248)), module, Stages::TYPE_PARAMS + 3, 0.0, 1.0, 0.0));
addParam(createParam<TL1105>(mm2px(Vec(49.95446, 32.37248)), module, Stages::TYPE_PARAMS + 4, 0.0, 1.0, 0.0));
addParam(createParam<TL1105>(mm2px(Vec(61.39424, 32.37248)), module, Stages::TYPE_PARAMS + 5, 0.0, 1.0, 0.0));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(3.36193, 43.06508)), module, Stages::LEVEL_PARAMS + 0, 0.0, 1.0, 0.5));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(14.81619, 43.06508)), module, Stages::LEVEL_PARAMS + 1, 0.0, 1.0, 0.5));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(26.26975, 43.06508)), module, Stages::LEVEL_PARAMS + 2, 0.0, 1.0, 0.5));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(37.70265, 43.06508)), module, Stages::LEVEL_PARAMS + 3, 0.0, 1.0, 0.5));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(49.15759, 43.06508)), module, Stages::LEVEL_PARAMS + 4, 0.0, 1.0, 0.5));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(60.61184, 43.06508)), module, Stages::LEVEL_PARAMS + 5, 0.0, 1.0, 0.5));
addInput(createPort<PJ301MPort>(mm2px(Vec(2.70756, 77.75277)), PortWidget::INPUT, module, Stages::LEVEL_INPUTS + 0));
addInput(createPort<PJ301MPort>(mm2px(Vec(14.14734, 77.75277)), PortWidget::INPUT, module, Stages::LEVEL_INPUTS + 1));
addInput(createPort<PJ301MPort>(mm2px(Vec(25.58781, 77.75277)), PortWidget::INPUT, module, Stages::LEVEL_INPUTS + 2));
addInput(createPort<PJ301MPort>(mm2px(Vec(37.04896, 77.75277)), PortWidget::INPUT, module, Stages::LEVEL_INPUTS + 3));
addInput(createPort<PJ301MPort>(mm2px(Vec(48.48943, 77.75277)), PortWidget::INPUT, module, Stages::LEVEL_INPUTS + 4));
addInput(createPort<PJ301MPort>(mm2px(Vec(59.92921, 77.75277)), PortWidget::INPUT, module, Stages::LEVEL_INPUTS + 5));
addInput(createPort<PJ301MPort>(mm2px(Vec(2.70756, 92.35239)), PortWidget::INPUT, module, Stages::GATE_INPUTS + 0));
addInput(createPort<PJ301MPort>(mm2px(Vec(14.14734, 92.35239)), PortWidget::INPUT, module, Stages::GATE_INPUTS + 1));
addInput(createPort<PJ301MPort>(mm2px(Vec(25.58781, 92.35239)), PortWidget::INPUT, module, Stages::GATE_INPUTS + 2));
addInput(createPort<PJ301MPort>(mm2px(Vec(37.04896, 92.35239)), PortWidget::INPUT, module, Stages::GATE_INPUTS + 3));
addInput(createPort<PJ301MPort>(mm2px(Vec(48.48943, 92.35239)), PortWidget::INPUT, module, Stages::GATE_INPUTS + 4));
addInput(createPort<PJ301MPort>(mm2px(Vec(59.92921, 92.35239)), PortWidget::INPUT, module, Stages::GATE_INPUTS + 5));
addOutput(createPort<PJ301MPort>(mm2px(Vec(2.70756, 106.95203)), PortWidget::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 0));
addOutput(createPort<PJ301MPort>(mm2px(Vec(14.14734, 106.95203)), PortWidget::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 1));
addOutput(createPort<PJ301MPort>(mm2px(Vec(25.58781, 106.95203)), PortWidget::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 2));
addOutput(createPort<PJ301MPort>(mm2px(Vec(37.04896, 106.95203)), PortWidget::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 3));
addOutput(createPort<PJ301MPort>(mm2px(Vec(48.48943, 106.95203)), PortWidget::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 4));
addOutput(createPort<PJ301MPort>(mm2px(Vec(59.92921, 106.95203)), PortWidget::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 5));
addParam(createParam<Trimpot>(mm2px(Vec(3.72965, 13.98158)), module, Stages::SHAPE_PARAMS + 0));
addParam(createParam<Trimpot>(mm2px(Vec(15.17012, 13.98158)), module, Stages::SHAPE_PARAMS + 1));
addParam(createParam<Trimpot>(mm2px(Vec(26.6099, 13.98158)), module, Stages::SHAPE_PARAMS + 2));
addParam(createParam<Trimpot>(mm2px(Vec(38.07174, 13.98158)), module, Stages::SHAPE_PARAMS + 3));
addParam(createParam<Trimpot>(mm2px(Vec(49.51152, 13.98158)), module, Stages::SHAPE_PARAMS + 4));
addParam(createParam<Trimpot>(mm2px(Vec(60.95199, 13.98158)), module, Stages::SHAPE_PARAMS + 5));
addParam(createParam<TL1105>(mm2px(Vec(4.17259, 32.37248)), module, Stages::TYPE_PARAMS + 0));
addParam(createParam<TL1105>(mm2px(Vec(15.61237, 32.37248)), module, Stages::TYPE_PARAMS + 1));
addParam(createParam<TL1105>(mm2px(Vec(27.05284, 32.37248)), module, Stages::TYPE_PARAMS + 2));
addParam(createParam<TL1105>(mm2px(Vec(38.51399, 32.37248)), module, Stages::TYPE_PARAMS + 3));
addParam(createParam<TL1105>(mm2px(Vec(49.95446, 32.37248)), module, Stages::TYPE_PARAMS + 4));
addParam(createParam<TL1105>(mm2px(Vec(61.39424, 32.37248)), module, Stages::TYPE_PARAMS + 5));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(3.36193, 43.06508)), module, Stages::LEVEL_PARAMS + 0));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(14.81619, 43.06508)), module, Stages::LEVEL_PARAMS + 1));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(26.26975, 43.06508)), module, Stages::LEVEL_PARAMS + 2));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(37.70265, 43.06508)), module, Stages::LEVEL_PARAMS + 3));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(49.15759, 43.06508)), module, Stages::LEVEL_PARAMS + 4));
addParam(createParam<LEDSliderGreen>(mm2px(Vec(60.61184, 43.06508)), module, Stages::LEVEL_PARAMS + 5));
addInput(createInput<PJ301MPort>(mm2px(Vec(2.70756, 77.75277)), module, Stages::LEVEL_INPUTS + 0));
addInput(createInput<PJ301MPort>(mm2px(Vec(14.14734, 77.75277)), module, Stages::LEVEL_INPUTS + 1));
addInput(createInput<PJ301MPort>(mm2px(Vec(25.58781, 77.75277)), module, Stages::LEVEL_INPUTS + 2));
addInput(createInput<PJ301MPort>(mm2px(Vec(37.04896, 77.75277)), module, Stages::LEVEL_INPUTS + 3));
addInput(createInput<PJ301MPort>(mm2px(Vec(48.48943, 77.75277)), module, Stages::LEVEL_INPUTS + 4));
addInput(createInput<PJ301MPort>(mm2px(Vec(59.92921, 77.75277)), module, Stages::LEVEL_INPUTS + 5));
addInput(createInput<PJ301MPort>(mm2px(Vec(2.70756, 92.35239)), module, Stages::GATE_INPUTS + 0));
addInput(createInput<PJ301MPort>(mm2px(Vec(14.14734, 92.35239)), module, Stages::GATE_INPUTS + 1));
addInput(createInput<PJ301MPort>(mm2px(Vec(25.58781, 92.35239)), module, Stages::GATE_INPUTS + 2));
addInput(createInput<PJ301MPort>(mm2px(Vec(37.04896, 92.35239)), module, Stages::GATE_INPUTS + 3));
addInput(createInput<PJ301MPort>(mm2px(Vec(48.48943, 92.35239)), module, Stages::GATE_INPUTS + 4));
addInput(createInput<PJ301MPort>(mm2px(Vec(59.92921, 92.35239)), module, Stages::GATE_INPUTS + 5));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(2.70756, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 0));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(14.14734, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 1));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(25.58781, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 2));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(37.04896, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 3));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(48.48943, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 4));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(59.92921, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 5));

addChild(createLight<MediumLight<GreenRedLight>>(mm2px(Vec(5.27737, 26.74447)), module, Stages::TYPE_LIGHTS + 0 * 2));
addChild(createLight<MediumLight<GreenRedLight>>(mm2px(Vec(16.73784, 26.74447)), module, Stages::TYPE_LIGHTS + 1 * 2));


+ 64
- 54
src/Tides.cpp View File

@@ -47,11 +47,11 @@ struct Tides : Module {
tides::Generator generator;
int frame = 0;
uint8_t lastGate;
SchmittTrigger modeTrigger;
SchmittTrigger rangeTrigger;
dsp::SchmittTrigger modeTrigger;
dsp::SchmittTrigger rangeTrigger;

Tides();
void step() override;
void process(const ProcessArgs &args) override;


void onReset() override {
@@ -61,8 +61,8 @@ struct Tides : Module {
}

void onRandomize() override {
generator.set_range((tides::GeneratorRange) (randomu32() % 3));
generator.set_mode((tides::GeneratorMode) (randomu32() % 3));
generator.set_range((tides::GeneratorRange) (random::u32() % 3));
generator.set_mode((tides::GeneratorMode) (random::u32() % 3));
}

json_t *dataToJson() override {
@@ -94,16 +94,25 @@ struct Tides : Module {
};


Tides::Tides() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
Tides::Tides() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Tides::MODE_PARAM, 0.0, 1.0, 0.0);
configParam(Tides::RANGE_PARAM, 0.0, 1.0, 0.0);
configParam(Tides::FREQUENCY_PARAM, -48.0, 48.0, 0.0);
configParam(Tides::FM_PARAM, -12.0, 12.0, 0.0);
configParam(Tides::SHAPE_PARAM, -1.0, 1.0, 0.0);
configParam(Tides::SLOPE_PARAM, -1.0, 1.0, 0.0);
configParam(Tides::SMOOTHNESS_PARAM, -1.0, 1.0, 0.0);

memset(&generator, 0, sizeof(generator));
generator.Init();
generator.set_sync(false);
onReset();
}

void Tides::step() {
void Tides::process(const ProcessArgs &args) {
tides::GeneratorMode mode = generator.mode();
if (modeTrigger.process(params[MODE_PARAM].value)) {
if (modeTrigger.process(params[MODE_PARAM].getValue())) {
mode = (tides::GeneratorMode) (((int)mode - 1 + 3) % 3);
generator.set_mode(mode);
}
@@ -111,7 +120,7 @@ void Tides::step() {
lights[MODE_RED_LIGHT].value = (mode == 0) ? 1.0 : 0.0;

tides::GeneratorRange range = generator.range();
if (rangeTrigger.process(params[RANGE_PARAM].value)) {
if (rangeTrigger.process(params[RANGE_PARAM].getValue())) {
range = (tides::GeneratorRange) (((int)range - 1 + 3) % 3);
generator.set_range(range);
}
@@ -123,18 +132,18 @@ void Tides::step() {
frame = 0;

// Pitch
float pitch = params[FREQUENCY_PARAM].value;
pitch += 12.0 * inputs[PITCH_INPUT].value;
pitch += params[FM_PARAM].value * inputs[FM_INPUT].normalize(0.1) / 5.0;
float pitch = params[FREQUENCY_PARAM].getValue();
pitch += 12.0 * inputs[PITCH_INPUT].getVoltage();
pitch += params[FM_PARAM].getValue() * inputs[FM_INPUT].getNormalVoltage(0.1) / 5.0;
pitch += 60.0;
// Scale to the global sample rate
pitch += log2f(48000.0 / engineGetSampleRate()) * 12.0;
pitch += log2f(48000.0 / args.sampleRate) * 12.0;
generator.set_pitch((int) clamp(pitch * 0x80, (float) -0x8000, (float) 0x7fff));

// Slope, smoothness, pitch
int16_t shape = clamp(params[SHAPE_PARAM].value + inputs[SHAPE_INPUT].value / 5.0f, -1.0f, 1.0f) * 0x7fff;
int16_t slope = clamp(params[SLOPE_PARAM].value + inputs[SLOPE_INPUT].value / 5.0f, -1.0f, 1.0f) * 0x7fff;
int16_t smoothness = clamp(params[SMOOTHNESS_PARAM].value + inputs[SMOOTHNESS_INPUT].value / 5.0f, -1.0f, 1.0f) * 0x7fff;
int16_t shape = clamp(params[SHAPE_PARAM].getValue() + inputs[SHAPE_INPUT].getVoltage() / 5.0f, -1.0f, 1.0f) * 0x7fff;
int16_t slope = clamp(params[SLOPE_PARAM].getValue() + inputs[SLOPE_INPUT].getVoltage() / 5.0f, -1.0f, 1.0f) * 0x7fff;
int16_t smoothness = clamp(params[SMOOTHNESS_PARAM].getValue() + inputs[SMOOTHNESS_INPUT].getVoltage() / 5.0f, -1.0f, 1.0f) * 0x7fff;
generator.set_shape(shape);
generator.set_slope(slope);
generator.set_smoothness(smoothness);
@@ -142,23 +151,23 @@ void Tides::step() {
// Sync
// Slight deviation from spec here.
// Instead of toggling sync by holding the range button, just enable it if the clock port is plugged in.
generator.set_sync(inputs[CLOCK_INPUT].active && !sheep);
generator.set_sync(inputs[CLOCK_INPUT].isConnected() && !sheep);

// Generator
generator.Process(sheep);
}

// Level
uint16_t level = clamp(inputs[LEVEL_INPUT].normalize(8.0) / 8.0f, 0.0f, 1.0f) * 0xffff;
uint16_t level = clamp(inputs[LEVEL_INPUT].getNormalVoltage(8.0) / 8.0f, 0.0f, 1.0f) * 0xffff;
if (level < 32)
level = 0;

uint8_t gate = 0;
if (inputs[FREEZE_INPUT].value >= 0.7)
if (inputs[FREEZE_INPUT].getVoltage() >= 0.7)
gate |= tides::CONTROL_FREEZE;
if (inputs[TRIG_INPUT].value >= 0.7)
if (inputs[TRIG_INPUT].getVoltage() >= 0.7)
gate |= tides::CONTROL_GATE;
if (inputs[CLOCK_INPUT].value >= 0.7)
if (inputs[CLOCK_INPUT].getVoltage() >= 0.7)
gate |= tides::CONTROL_CLOCK;
if (!(lastGate & tides::CONTROL_CLOCK) && (gate & tides::CONTROL_CLOCK))
gate |= tides::CONTROL_GATE_RISING;
@@ -177,33 +186,34 @@ void Tides::step() {
float unif = (float) uni / 0xffff;
float bif = (float) bi / 0x8000;

outputs[HIGH_OUTPUT].value = sample.flags & tides::FLAG_END_OF_ATTACK ? 0.0 : 5.0;
outputs[LOW_OUTPUT].value = sample.flags & tides::FLAG_END_OF_RELEASE ? 0.0 : 5.0;
outputs[UNI_OUTPUT].value = unif * 8.0;
outputs[BI_OUTPUT].value = bif * 5.0;
outputs[HIGH_OUTPUT].setVoltage(sample.flags & tides::FLAG_END_OF_ATTACK ? 0.0 : 5.0);
outputs[LOW_OUTPUT].setVoltage(sample.flags & tides::FLAG_END_OF_RELEASE ? 0.0 : 5.0);
outputs[UNI_OUTPUT].setVoltage(unif * 8.0);
outputs[BI_OUTPUT].setVoltage(bif * 5.0);

if (sample.flags & tides::FLAG_END_OF_ATTACK)
unif *= -1.0;
lights[PHASE_GREEN_LIGHT].setBrightnessSmooth(fmaxf(0.0, unif));
lights[PHASE_RED_LIGHT].setBrightnessSmooth(fmaxf(0.0, -unif));
lights[PHASE_GREEN_LIGHT].setSmoothBrightness(fmaxf(0.0, unif), args.sampleTime);
lights[PHASE_RED_LIGHT].setSmoothBrightness(fmaxf(0.0, -unif), args.sampleTime);
}


struct TidesWidget : ModuleWidget {
SVGPanel *tidesPanel;
SVGPanel *sheepPanel;
SvgPanel *tidesPanel;
SvgPanel *sheepPanel;

TidesWidget(Tides *module) : ModuleWidget(module) {
TidesWidget(Tides *module) {
setModule(module);
box.size = Vec(15*14, 380);
{
tidesPanel = new SVGPanel();
tidesPanel->setBackground(SVG::load(assetPlugin(pluginInstance, "res/Tides.svg")));
tidesPanel = new SvgPanel();
tidesPanel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Tides.svg")));
tidesPanel->box.size = box.size;
addChild(tidesPanel);
}
{
sheepPanel = new SVGPanel();
sheepPanel->setBackground(SVG::load(assetPlugin(pluginInstance, "res/Sheep.svg")));
sheepPanel = new SvgPanel();
sheepPanel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Sheep.svg")));
sheepPanel->box.size = box.size;
addChild(sheepPanel);
}
@@ -213,31 +223,31 @@ struct TidesWidget : ModuleWidget {
addChild(createWidget<ScrewSilver>(Vec(15, 365)));
addChild(createWidget<ScrewSilver>(Vec(180, 365)));

addParam(createParam<CKD6>(Vec(19, 52), module, Tides::MODE_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<CKD6>(Vec(19, 93), module, Tides::RANGE_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<CKD6>(Vec(19, 52), module, Tides::MODE_PARAM));
addParam(createParam<CKD6>(Vec(19, 93), module, Tides::RANGE_PARAM));

addParam(createParam<Rogan3PSGreen>(Vec(78, 60), module, Tides::FREQUENCY_PARAM, -48.0, 48.0, 0.0));
addParam(createParam<Rogan1PSGreen>(Vec(156, 66), module, Tides::FM_PARAM, -12.0, 12.0, 0.0));
addParam(createParam<Rogan3PSGreen>(Vec(78, 60), module, Tides::FREQUENCY_PARAM));
addParam(createParam<Rogan1PSGreen>(Vec(156, 66), module, Tides::FM_PARAM));

addParam(createParam<Rogan1PSWhite>(Vec(13, 155), module, Tides::SHAPE_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(85, 155), module, Tides::SLOPE_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(156, 155), module, Tides::SMOOTHNESS_PARAM, -1.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(13, 155), module, Tides::SHAPE_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(85, 155), module, Tides::SLOPE_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(156, 155), module, Tides::SMOOTHNESS_PARAM));

addInput(createPort<PJ301MPort>(Vec(21, 219), PortWidget::INPUT, module, Tides::SHAPE_INPUT));
addInput(createPort<PJ301MPort>(Vec(93, 219), PortWidget::INPUT, module, Tides::SLOPE_INPUT));
addInput(createPort<PJ301MPort>(Vec(164, 219), PortWidget::INPUT, module, Tides::SMOOTHNESS_INPUT));
addInput(createInput<PJ301MPort>(Vec(21, 219), module, Tides::SHAPE_INPUT));
addInput(createInput<PJ301MPort>(Vec(93, 219), module, Tides::SLOPE_INPUT));
addInput(createInput<PJ301MPort>(Vec(164, 219), module, Tides::SMOOTHNESS_INPUT));

addInput(createPort<PJ301MPort>(Vec(21, 274), PortWidget::INPUT, module, Tides::TRIG_INPUT));
addInput(createPort<PJ301MPort>(Vec(57, 274), PortWidget::INPUT, module, Tides::FREEZE_INPUT));
addInput(createPort<PJ301MPort>(Vec(93, 274), PortWidget::INPUT, module, Tides::PITCH_INPUT));
addInput(createPort<PJ301MPort>(Vec(128, 274), PortWidget::INPUT, module, Tides::FM_INPUT));
addInput(createPort<PJ301MPort>(Vec(164, 274), PortWidget::INPUT, module, Tides::LEVEL_INPUT));
addInput(createInput<PJ301MPort>(Vec(21, 274), module, Tides::TRIG_INPUT));
addInput(createInput<PJ301MPort>(Vec(57, 274), module, Tides::FREEZE_INPUT));
addInput(createInput<PJ301MPort>(Vec(93, 274), module, Tides::PITCH_INPUT));
addInput(createInput<PJ301MPort>(Vec(128, 274), module, Tides::FM_INPUT));
addInput(createInput<PJ301MPort>(Vec(164, 274), module, Tides::LEVEL_INPUT));

addInput(createPort<PJ301MPort>(Vec(21, 316), PortWidget::INPUT, module, Tides::CLOCK_INPUT));
addOutput(createPort<PJ301MPort>(Vec(57, 316), PortWidget::OUTPUT, module, Tides::HIGH_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(93, 316), PortWidget::OUTPUT, module, Tides::LOW_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(128, 316), PortWidget::OUTPUT, module, Tides::UNI_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(164, 316), PortWidget::OUTPUT, module, Tides::BI_OUTPUT));
addInput(createInput<PJ301MPort>(Vec(21, 316), module, Tides::CLOCK_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(57, 316), module, Tides::HIGH_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(93, 316), module, Tides::LOW_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(128, 316), module, Tides::UNI_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(164, 316), module, Tides::BI_OUTPUT));

addChild(createLight<MediumLight<GreenRedLight>>(Vec(56, 61), module, Tides::MODE_GREEN_LIGHT));
addChild(createLight<MediumLight<GreenRedLight>>(Vec(56, 82), module, Tides::PHASE_GREEN_LIGHT));


+ 56
- 40
src/Tides2.cpp View File

@@ -84,9 +84,9 @@ struct Tides2 : Module {
int range;
tides2::OutputMode output_mode;
tides2::RampMode ramp_mode;
BooleanTrigger rangeTrigger;
BooleanTrigger modeTrigger;
BooleanTrigger rampTrigger;
dsp::BooleanTrigger rangeTrigger;
dsp::BooleanTrigger modeTrigger;
dsp::BooleanTrigger rampTrigger;

// Buffers
tides2::PolySlopeGenerator::OutputSample out[tides2::kBlockSize];
@@ -99,7 +99,22 @@ struct Tides2 : Module {
tides2::OutputMode previous_output_mode = tides2::OUTPUT_MODE_GATES;
uint8_t frame = 0;

Tides2() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
Tides2() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Tides2::RANGE_PARAM, 0.0, 1.0, 0.0);
configParam(Tides2::MODE_PARAM, 0.0, 1.0, 0.0);
configParam(Tides2::FREQUENCY_PARAM, -48, 48, 0.0);
configParam(Tides2::SHAPE_PARAM, 0.0, 1.0, 0.5);
configParam(Tides2::RAMP_PARAM, 0.0, 1.0, 0.0);
configParam(Tides2::SMOOTHNESS_PARAM, 0.0, 1.0, 0.5);
configParam(Tides2::SLOPE_PARAM, 0.0, 1.0, 0.5);
configParam(Tides2::SHIFT_PARAM, 0.0, 1.0, 0.5);
configParam(Tides2::SLOPE_CV_PARAM, -1.0, 1.0, 0.0);
configParam(Tides2::FREQUENCY_CV_PARAM, -1.0, 1.0, 0.0);
configParam(Tides2::SMOOTHNESS_CV_PARAM, -1.0, 1.0, 0.0);
configParam(Tides2::SHAPE_CV_PARAM, -1.0, 1.0, 0.0);
configParam(Tides2::SHIFT_CV_PARAM, -1.0, 1.0, 0.0);

poly_slope_generator.Init();
ratio_index_quantizer.Init();
memset(&out, 0, sizeof(out));
@@ -116,13 +131,13 @@ struct Tides2 : Module {
}

void onRandomize() override {
range = randomu32() % 3;
output_mode = (tides2::OutputMode) (randomu32() % 4);
ramp_mode = (tides2::RampMode) (randomu32() % 3);
range = random::u32() % 3;
output_mode = (tides2::OutputMode) (random::u32() % 4);
ramp_mode = (tides2::RampMode) (random::u32() % 3);
}

void onSampleRateChange() override {
ramp_extractor.Init(engineGetSampleRate(), 40.f / engineGetSampleRate());
ramp_extractor.Init(APP->engine->getSampleRate(), 40.f / APP->engine->getSampleRate());
}

json_t *dataToJson() override {
@@ -149,23 +164,23 @@ struct Tides2 : Module {
ramp_mode = (tides2::RampMode) json_integer_value(rampJ);
}

void step() override {
void process(const ProcessArgs &args) override {
// Switches
if (rangeTrigger.process(params[RANGE_PARAM].value > 0.f)) {
if (rangeTrigger.process(params[RANGE_PARAM].getValue() > 0.f)) {
range = (range + 1) % 3;
}
if (modeTrigger.process(params[MODE_PARAM].value > 0.f)) {
if (modeTrigger.process(params[MODE_PARAM].getValue() > 0.f)) {
output_mode = (tides2::OutputMode) ((output_mode + 1) % 4);
}
if (rampTrigger.process(params[RAMP_PARAM].value > 0.f)) {
if (rampTrigger.process(params[RAMP_PARAM].getValue() > 0.f)) {
ramp_mode = (tides2::RampMode) ((ramp_mode + 1) % 3);
}

// Input gates
trig_flags[frame] = stmlib::ExtractGateFlags(previous_trig_flag, inputs[TRIG_INPUT].value >= 1.7f);
trig_flags[frame] = stmlib::ExtractGateFlags(previous_trig_flag, inputs[TRIG_INPUT].getVoltage() >= 1.7f);
previous_trig_flag = trig_flags[frame];

clock_flags[frame] = stmlib::ExtractGateFlags(previous_clock_flag, inputs[CLOCK_INPUT].value >= 1.7f);
clock_flags[frame] = stmlib::ExtractGateFlags(previous_clock_flag, inputs[CLOCK_INPUT].getVoltage() >= 1.7f);
previous_clock_flag = clock_flags[frame];

// Process block
@@ -173,14 +188,14 @@ struct Tides2 : Module {
frame = 0;

tides2::Range range_mode = (range < 2) ? tides2::RANGE_CONTROL : tides2::RANGE_AUDIO;
float note = clamp(params[FREQUENCY_PARAM].value + 12.f * inputs[V_OCT_INPUT].value, -96.f, 96.f);
float fm = clamp(params[FREQUENCY_CV_PARAM].value * inputs[FREQUENCY_INPUT].value * 12.f, -96.f, 96.f);
float note = clamp(params[FREQUENCY_PARAM].getValue() + 12.f * inputs[V_OCT_INPUT].getVoltage(), -96.f, 96.f);
float fm = clamp(params[FREQUENCY_CV_PARAM].getValue() * inputs[FREQUENCY_INPUT].getVoltage() * 12.f, -96.f, 96.f);
float transposition = note + fm;

float ramp[tides2::kBlockSize];
float frequency;

if (inputs[CLOCK_INPUT].active) {
if (inputs[CLOCK_INPUT].isConnected()) {
if (must_reset_ramp_extractor) {
ramp_extractor.Reset();
}
@@ -196,15 +211,15 @@ struct Tides2 : Module {
must_reset_ramp_extractor = false;
}
else {
frequency = kRootScaled[range] / engineGetSampleRate() * stmlib::SemitonesToRatio(transposition);
frequency = kRootScaled[range] / args.sampleRate * stmlib::SemitonesToRatio(transposition);
must_reset_ramp_extractor = true;
}

// Get parameters
float slope = clamp(params[SLOPE_PARAM].value + cubic(params[SLOPE_CV_PARAM].value) * inputs[SLOPE_INPUT].value / 10.f, 0.f, 1.f);
float shape = clamp(params[SHAPE_PARAM].value + cubic(params[SHAPE_CV_PARAM].value) * inputs[SHAPE_INPUT].value / 10.f, 0.f, 1.f);
float smoothness = clamp(params[SMOOTHNESS_PARAM].value + cubic(params[SMOOTHNESS_CV_PARAM].value) * inputs[SMOOTHNESS_INPUT].value / 10.f, 0.f, 1.f);
float shift = clamp(params[SHIFT_PARAM].value + cubic(params[SHIFT_CV_PARAM].value) * inputs[SHIFT_INPUT].value / 10.f, 0.f, 1.f);
float slope = clamp(params[SLOPE_PARAM].getValue() + dsp::cubic(params[SLOPE_CV_PARAM].getValue()) * inputs[SLOPE_INPUT].getVoltage() / 10.f, 0.f, 1.f);
float shape = clamp(params[SHAPE_PARAM].getValue() + dsp::cubic(params[SHAPE_CV_PARAM].getValue()) * inputs[SHAPE_INPUT].getVoltage() / 10.f, 0.f, 1.f);
float smoothness = clamp(params[SMOOTHNESS_PARAM].getValue() + dsp::cubic(params[SMOOTHNESS_CV_PARAM].getValue()) * inputs[SMOOTHNESS_INPUT].getVoltage() / 10.f, 0.f, 1.f);
float shift = clamp(params[SHIFT_PARAM].getValue() + dsp::cubic(params[SHIFT_CV_PARAM].getValue()) * inputs[SHIFT_INPUT].getVoltage() / 10.f, 0.f, 1.f);

if (output_mode != previous_output_mode) {
poly_slope_generator.Reset();
@@ -222,7 +237,7 @@ struct Tides2 : Module {
smoothness,
shift,
trig_flags,
!inputs[TRIG_INPUT].active && inputs[CLOCK_INPUT].active ? ramp : NULL,
!inputs[TRIG_INPUT].isConnected() && inputs[CLOCK_INPUT].isConnected() ? ramp : NULL,
out,
tides2::kBlockSize);

@@ -238,35 +253,36 @@ struct Tides2 : Module {
// Outputs
for (int i = 0; i < 4; i++) {
float value = out[frame].channel[i];
outputs[OUT_OUTPUTS + i].value = value;
lights[OUTPUT_LIGHTS + i].setBrightnessSmooth(value);
outputs[OUT_OUTPUTS + i].setVoltage(value);
lights[OUTPUT_LIGHTS + i].setSmoothBrightness(value, args.sampleTime);
}
}
};


struct Tides2Widget : ModuleWidget {
Tides2Widget(Tides2 *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Tides2.svg")));
Tides2Widget(Tides2 *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Tides2.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(createParamCentered<TL1105>(mm2px(Vec(7.425, 16.15)), module, Tides2::RANGE_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<TL1105>(mm2px(Vec(63.325, 16.15)), module, Tides2::MODE_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<Rogan3PSWhite>(mm2px(Vec(16.325, 33.449)), module, Tides2::FREQUENCY_PARAM, -48, 48, 0.0));
addParam(createParamCentered<Rogan3PSWhite>(mm2px(Vec(54.425, 33.449)), module, Tides2::SHAPE_PARAM, 0.0, 1.0, 0.5));
addParam(createParamCentered<TL1105>(mm2px(Vec(35.375, 38.699)), module, Tides2::RAMP_PARAM, 0.0, 1.0, 0.0));
addParam(createParamCentered<Rogan1PSWhite>(mm2px(Vec(35.375, 55.549)), module, Tides2::SMOOTHNESS_PARAM, 0.0, 1.0, 0.5));
addParam(createParamCentered<Rogan1PSWhite>(mm2px(Vec(11.575, 60.599)), module, Tides2::SLOPE_PARAM, 0.0, 1.0, 0.5));
addParam(createParamCentered<Rogan1PSWhite>(mm2px(Vec(59.175, 60.599)), module, Tides2::SHIFT_PARAM, 0.0, 1.0, 0.5));
addParam(createParamCentered<Trimpot>(mm2px(Vec(9.276, 80.599)), module, Tides2::SLOPE_CV_PARAM, -1.0, 1.0, 0.0));
addParam(createParamCentered<Trimpot>(mm2px(Vec(22.324, 80.599)), module, Tides2::FREQUENCY_CV_PARAM, -1.0, 1.0, 0.0));
addParam(createParamCentered<Trimpot>(mm2px(Vec(35.375, 80.599)), module, Tides2::SMOOTHNESS_CV_PARAM, -1.0, 1.0, 0.0));
addParam(createParamCentered<Trimpot>(mm2px(Vec(48.425, 80.599)), module, Tides2::SHAPE_CV_PARAM, -1.0, 1.0, 0.0));
addParam(createParamCentered<Trimpot>(mm2px(Vec(61.475, 80.599)), module, Tides2::SHIFT_CV_PARAM, -1.0, 1.0, 0.0));
addParam(createParamCentered<TL1105>(mm2px(Vec(7.425, 16.15)), module, Tides2::RANGE_PARAM));
addParam(createParamCentered<TL1105>(mm2px(Vec(63.325, 16.15)), module, Tides2::MODE_PARAM));
addParam(createParamCentered<Rogan3PSWhite>(mm2px(Vec(16.325, 33.449)), module, Tides2::FREQUENCY_PARAM));
addParam(createParamCentered<Rogan3PSWhite>(mm2px(Vec(54.425, 33.449)), module, Tides2::SHAPE_PARAM));
addParam(createParamCentered<TL1105>(mm2px(Vec(35.375, 38.699)), module, Tides2::RAMP_PARAM));
addParam(createParamCentered<Rogan1PSWhite>(mm2px(Vec(35.375, 55.549)), module, Tides2::SMOOTHNESS_PARAM));
addParam(createParamCentered<Rogan1PSWhite>(mm2px(Vec(11.575, 60.599)), module, Tides2::SLOPE_PARAM));
addParam(createParamCentered<Rogan1PSWhite>(mm2px(Vec(59.175, 60.599)), module, Tides2::SHIFT_PARAM));
addParam(createParamCentered<Trimpot>(mm2px(Vec(9.276, 80.599)), module, Tides2::SLOPE_CV_PARAM));
addParam(createParamCentered<Trimpot>(mm2px(Vec(22.324, 80.599)), module, Tides2::FREQUENCY_CV_PARAM));
addParam(createParamCentered<Trimpot>(mm2px(Vec(35.375, 80.599)), module, Tides2::SMOOTHNESS_CV_PARAM));
addParam(createParamCentered<Trimpot>(mm2px(Vec(48.425, 80.599)), module, Tides2::SHAPE_CV_PARAM));
addParam(createParamCentered<Trimpot>(mm2px(Vec(61.475, 80.599)), module, Tides2::SHIFT_CV_PARAM));

addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.775, 96.499)), module, Tides2::SLOPE_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.225, 96.499)), module, Tides2::FREQUENCY_INPUT));


+ 48
- 37
src/Veils.cpp View File

@@ -39,28 +39,38 @@ struct Veils : Module {
NUM_LIGHTS
};

Veils() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
void step() override;
Veils() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Veils::GAIN1_PARAM, 0.0, 1.0, 0.0);
configParam(Veils::GAIN2_PARAM, 0.0, 1.0, 0.0);
configParam(Veils::GAIN3_PARAM, 0.0, 1.0, 0.0);
configParam(Veils::GAIN4_PARAM, 0.0, 1.0, 0.0);
configParam(Veils::RESPONSE1_PARAM, 0.0, 1.0, 1.0);
configParam(Veils::RESPONSE2_PARAM, 0.0, 1.0, 1.0);
configParam(Veils::RESPONSE3_PARAM, 0.0, 1.0, 1.0);
configParam(Veils::RESPONSE4_PARAM, 0.0, 1.0, 1.0);
}
void process(const ProcessArgs &args) override;
};


void Veils::step() {
void Veils::process(const ProcessArgs &args) {
float out = 0.0;

for (int i = 0; i < 4; i++) {
float in = inputs[IN1_INPUT + i].value * params[GAIN1_PARAM + i].value;
if (inputs[CV1_INPUT + i].active) {
float linear = fmaxf(inputs[CV1_INPUT + i].value / 5.0, 0.0);
float in = inputs[IN1_INPUT + i].getVoltage() * params[GAIN1_PARAM + i].getValue();
if (inputs[CV1_INPUT + i].isConnected()) {
float linear = fmaxf(inputs[CV1_INPUT + i].getVoltage() / 5.0, 0.0);
linear = clamp(linear, 0.0f, 2.0f);
const float base = 200.0;
float exponential = rescale(powf(base, linear / 2.0f), 1.0f, base, 0.0f, 10.0f);
in *= crossfade(exponential, linear, params[RESPONSE1_PARAM + i].value);
in *= crossfade(exponential, linear, params[RESPONSE1_PARAM + i].getValue());
}
out += in;
lights[OUT1_POS_LIGHT + 2*i].setBrightnessSmooth(fmaxf(0.0, out / 5.0));
lights[OUT1_NEG_LIGHT + 2*i].setBrightnessSmooth(fmaxf(0.0, -out / 5.0));
if (outputs[OUT1_OUTPUT + i].active) {
outputs[OUT1_OUTPUT + i].value = out;
lights[OUT1_POS_LIGHT + 2*i].setSmoothBrightness(fmaxf(0.0, out / 5.0), args.sampleTime);
lights[OUT1_NEG_LIGHT + 2*i].setSmoothBrightness(fmaxf(0.0, -out / 5.0), args.sampleTime);
if (outputs[OUT1_OUTPUT + i].isConnected()) {
outputs[OUT1_OUTPUT + i].setVoltage(out);
out = 0.0;
}
}
@@ -68,38 +78,39 @@ void Veils::step() {


struct VeilsWidget : ModuleWidget {
VeilsWidget(Veils *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Veils.svg")));
VeilsWidget(Veils *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Veils.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(150, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));
addChild(createWidget<ScrewSilver>(Vec(150, 365)));

addParam(createParam<Rogan1PSWhite>(Vec(8, 52), module, Veils::GAIN1_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(8, 131), module, Veils::GAIN2_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(8, 210), module, Veils::GAIN3_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Rogan1PSWhite>(Vec(8, 288), module, Veils::GAIN4_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(72, 56), module, Veils::RESPONSE1_PARAM, 0.0, 1.0, 1.0));
addParam(createParam<Trimpot>(Vec(72, 135), module, Veils::RESPONSE2_PARAM, 0.0, 1.0, 1.0));
addParam(createParam<Trimpot>(Vec(72, 214), module, Veils::RESPONSE3_PARAM, 0.0, 1.0, 1.0));
addParam(createParam<Trimpot>(Vec(72, 292), module, Veils::RESPONSE4_PARAM, 0.0, 1.0, 1.0));
addInput(createPort<PJ301MPort>(Vec(110, 41), PortWidget::INPUT, module, Veils::IN1_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 120), PortWidget::INPUT, module, Veils::IN2_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 198), PortWidget::INPUT, module, Veils::IN3_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 277), PortWidget::INPUT, module, Veils::IN4_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 80), PortWidget::INPUT, module, Veils::CV1_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 159), PortWidget::INPUT, module, Veils::CV2_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 238), PortWidget::INPUT, module, Veils::CV3_INPUT));
addInput(createPort<PJ301MPort>(Vec(110, 316), PortWidget::INPUT, module, Veils::CV4_INPUT));
addOutput(createPort<PJ301MPort>(Vec(144, 41), PortWidget::OUTPUT, module, Veils::OUT1_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(144, 120), PortWidget::OUTPUT, module, Veils::OUT2_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(144, 198), PortWidget::OUTPUT, module, Veils::OUT3_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(144, 277), PortWidget::OUTPUT, module, Veils::OUT4_OUTPUT));
addParam(createParam<Rogan1PSWhite>(Vec(8, 52), module, Veils::GAIN1_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(8, 131), module, Veils::GAIN2_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(8, 210), module, Veils::GAIN3_PARAM));
addParam(createParam<Rogan1PSWhite>(Vec(8, 288), module, Veils::GAIN4_PARAM));
addParam(createParam<Trimpot>(Vec(72, 56), module, Veils::RESPONSE1_PARAM));
addParam(createParam<Trimpot>(Vec(72, 135), module, Veils::RESPONSE2_PARAM));
addParam(createParam<Trimpot>(Vec(72, 214), module, Veils::RESPONSE3_PARAM));
addParam(createParam<Trimpot>(Vec(72, 292), module, Veils::RESPONSE4_PARAM));
addInput(createInput<PJ301MPort>(Vec(110, 41), module, Veils::IN1_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 120), module, Veils::IN2_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 198), module, Veils::IN3_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 277), module, Veils::IN4_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 80), module, Veils::CV1_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 159), module, Veils::CV2_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 238), module, Veils::CV3_INPUT));
addInput(createInput<PJ301MPort>(Vec(110, 316), module, Veils::CV4_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(144, 41), module, Veils::OUT1_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(144, 120), module, Veils::OUT2_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(144, 198), module, Veils::OUT3_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(144, 277), module, Veils::OUT4_OUTPUT));

addChild(createLight<MediumLight<GreenRedLight>>(Vec(152, 87), module, Veils::OUT1_POS_LIGHT));
addChild(createLight<MediumLight<GreenRedLight>>(Vec(152, 166), module, Veils::OUT2_POS_LIGHT));


+ 41
- 33
src/Warps.cpp View File

@@ -36,10 +36,10 @@ struct Warps : Module {
warps::Modulator modulator;
warps::ShortFrame inputFrames[60] = {};
warps::ShortFrame outputFrames[60] = {};
SchmittTrigger stateTrigger;
dsp::SchmittTrigger stateTrigger;

Warps();
void step() override;
void process(const ProcessArgs &args) override;

json_t *dataToJson() override {
json_t *rootJ = json_object();
@@ -63,20 +63,27 @@ struct Warps : Module {

void onRandomize() override {
warps::Parameters *p = modulator.mutable_parameters();
p->carrier_shape = randomu32() % 4;
p->carrier_shape = random::u32() % 4;
}
};


Warps::Warps() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
Warps::Warps() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(Warps::ALGORITHM_PARAM, 0.0, 8.0, 0.0);
configParam(Warps::TIMBRE_PARAM, 0.0, 1.0, 0.5);
configParam(Warps::STATE_PARAM, 0.0, 1.0, 0.0);
configParam(Warps::LEVEL1_PARAM, 0.0, 1.0, 1.0);
configParam(Warps::LEVEL2_PARAM, 0.0, 1.0, 1.0);

memset(&modulator, 0, sizeof(modulator));
modulator.Init(96000.0f);
}

void Warps::step() {
void Warps::process(const ProcessArgs &args) {
// State trigger
warps::Parameters *p = modulator.mutable_parameters();
if (stateTrigger.process(params[STATE_PARAM].value)) {
if (stateTrigger.process(params[STATE_PARAM].getValue())) {
p->carrier_shape = (p->carrier_shape + 1) % 4;
}
lights[CARRIER_GREEN_LIGHT].value = (p->carrier_shape == 1 || p->carrier_shape == 2) ? 1.0 : 0.0;
@@ -86,9 +93,9 @@ void Warps::step() {
if (++frame >= 60) {
frame = 0;

p->channel_drive[0] = clamp(params[LEVEL1_PARAM].value + inputs[LEVEL1_INPUT].value / 5.0f, 0.0f, 1.0f);
p->channel_drive[1] = clamp(params[LEVEL2_PARAM].value + inputs[LEVEL2_INPUT].value / 5.0f, 0.0f, 1.0f);
p->modulation_algorithm = clamp(params[ALGORITHM_PARAM].value / 8.0f + inputs[ALGORITHM_INPUT].value / 5.0f, 0.0f, 1.0f);
p->channel_drive[0] = clamp(params[LEVEL1_PARAM].getValue() + inputs[LEVEL1_INPUT].getVoltage() / 5.0f, 0.0f, 1.0f);
p->channel_drive[1] = clamp(params[LEVEL2_PARAM].getValue() + inputs[LEVEL2_INPUT].getVoltage() / 5.0f, 0.0f, 1.0f);
p->modulation_algorithm = clamp(params[ALGORITHM_PARAM].getValue() / 8.0f + inputs[ALGORITHM_INPUT].getVoltage() / 5.0f, 0.0f, 1.0f);

{
// TODO
@@ -99,21 +106,21 @@ void Warps::step() {
lights[ALGORITHM_LIGHT + 2].setBrightness(algorithmColor.b);
}

p->modulation_parameter = clamp(params[TIMBRE_PARAM].value + inputs[TIMBRE_INPUT].value / 5.0f, 0.0f, 1.0f);
p->modulation_parameter = clamp(params[TIMBRE_PARAM].getValue() + inputs[TIMBRE_INPUT].getVoltage() / 5.0f, 0.0f, 1.0f);

p->frequency_shift_pot = params[ALGORITHM_PARAM].value / 8.0;
p->frequency_shift_cv = clamp(inputs[ALGORITHM_INPUT].value / 5.0f, -1.0f, 1.0f);
p->frequency_shift_pot = params[ALGORITHM_PARAM].getValue() / 8.0;
p->frequency_shift_cv = clamp(inputs[ALGORITHM_INPUT].getVoltage() / 5.0f, -1.0f, 1.0f);
p->phase_shift = p->modulation_algorithm;
p->note = 60.0 * params[LEVEL1_PARAM].value + 12.0 * inputs[LEVEL1_INPUT].normalize(2.0) + 12.0;
p->note += log2f(96000.0f * engineGetSampleTime()) * 12.0f;
p->note = 60.0 * params[LEVEL1_PARAM].getValue() + 12.0 * inputs[LEVEL1_INPUT].getNormalVoltage(2.0) + 12.0;
p->note += log2f(96000.0f * args.sampleTime) * 12.0f;

modulator.Process(inputFrames, outputFrames, 60);
}

inputFrames[frame].l = clamp((int) (inputs[CARRIER_INPUT].value / 16.0 * 0x8000), -0x8000, 0x7fff);
inputFrames[frame].r = clamp((int) (inputs[MODULATOR_INPUT].value / 16.0 * 0x8000), -0x8000, 0x7fff);
outputs[MODULATOR_OUTPUT].value = (float)outputFrames[frame].l / 0x8000 * 5.0;
outputs[AUX_OUTPUT].value = (float)outputFrames[frame].r / 0x8000 * 5.0;
inputFrames[frame].l = clamp((int) (inputs[CARRIER_INPUT].getVoltage() / 16.0 * 0x8000), -0x8000, 0x7fff);
inputFrames[frame].r = clamp((int) (inputs[MODULATOR_INPUT].getVoltage() / 16.0 * 0x8000), -0x8000, 0x7fff);
outputs[MODULATOR_OUTPUT].setVoltage((float)outputFrames[frame].l / 0x8000 * 5.0);
outputs[AUX_OUTPUT].setVoltage((float)outputFrames[frame].r / 0x8000 * 5.0);
}


@@ -125,30 +132,31 @@ struct AlgorithmLight : RedGreenBlueLight {


struct WarpsWidget : ModuleWidget {
WarpsWidget(Warps *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(pluginInstance, "res/Warps.svg")));
WarpsWidget(Warps *module) {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Warps.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(120, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));
addChild(createWidget<ScrewSilver>(Vec(120, 365)));

addParam(createParam<Rogan6PSWhite>(Vec(29, 52), module, Warps::ALGORITHM_PARAM, 0.0, 8.0, 0.0));
addParam(createParam<Rogan6PSWhite>(Vec(29, 52), module, Warps::ALGORITHM_PARAM));

addParam(createParam<Rogan1PSWhite>(Vec(94, 173), module, Warps::TIMBRE_PARAM, 0.0, 1.0, 0.5));
addParam(createParam<TL1105>(Vec(16, 182), module, Warps::STATE_PARAM, 0.0, 1.0, 0.0));
addParam(createParam<Trimpot>(Vec(14, 213), module, Warps::LEVEL1_PARAM, 0.0, 1.0, 1.0));
addParam(createParam<Trimpot>(Vec(53, 213), module, Warps::LEVEL2_PARAM, 0.0, 1.0, 1.0));
addParam(createParam<Rogan1PSWhite>(Vec(94, 173), module, Warps::TIMBRE_PARAM));
addParam(createParam<TL1105>(Vec(16, 182), module, Warps::STATE_PARAM));
addParam(createParam<Trimpot>(Vec(14, 213), module, Warps::LEVEL1_PARAM));
addParam(createParam<Trimpot>(Vec(53, 213), module, Warps::LEVEL2_PARAM));

addInput(createPort<PJ301MPort>(Vec(8, 273), PortWidget::INPUT, module, Warps::LEVEL1_INPUT));
addInput(createPort<PJ301MPort>(Vec(44, 273), PortWidget::INPUT, module, Warps::LEVEL2_INPUT));
addInput(createPort<PJ301MPort>(Vec(80, 273), PortWidget::INPUT, module, Warps::ALGORITHM_INPUT));
addInput(createPort<PJ301MPort>(Vec(116, 273), PortWidget::INPUT, module, Warps::TIMBRE_INPUT));
addInput(createInput<PJ301MPort>(Vec(8, 273), module, Warps::LEVEL1_INPUT));
addInput(createInput<PJ301MPort>(Vec(44, 273), module, Warps::LEVEL2_INPUT));
addInput(createInput<PJ301MPort>(Vec(80, 273), module, Warps::ALGORITHM_INPUT));
addInput(createInput<PJ301MPort>(Vec(116, 273), module, Warps::TIMBRE_INPUT));

addInput(createPort<PJ301MPort>(Vec(8, 316), PortWidget::INPUT, module, Warps::CARRIER_INPUT));
addInput(createPort<PJ301MPort>(Vec(44, 316), PortWidget::INPUT, module, Warps::MODULATOR_INPUT));
addOutput(createPort<PJ301MPort>(Vec(80, 316), PortWidget::OUTPUT, module, Warps::MODULATOR_OUTPUT));
addOutput(createPort<PJ301MPort>(Vec(116, 316), PortWidget::OUTPUT, module, Warps::AUX_OUTPUT));
addInput(createInput<PJ301MPort>(Vec(8, 316), module, Warps::CARRIER_INPUT));
addInput(createInput<PJ301MPort>(Vec(44, 316), module, Warps::MODULATOR_INPUT));
addOutput(createOutput<PJ301MPort>(Vec(80, 316), module, Warps::MODULATOR_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(116, 316), module, Warps::AUX_OUTPUT));

addChild(createLight<SmallLight<GreenRedLight>>(Vec(21, 167), module, Warps::CARRIER_GREEN_LIGHT));



Loading…
Cancel
Save