@@ -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,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; |
@@ -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)); | |||
@@ -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 { | |||
@@ -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)); | |||
@@ -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)); | |||
@@ -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; | |||
} | |||
}; | |||
@@ -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); | |||
@@ -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)); | |||
@@ -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)); | |||
@@ -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)); | |||
@@ -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(¶meters[0], 2); | |||
processors[1].CopyParameters(¶meters[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(¶meters[0], 4); | |||
processors[1].CopyParameters(¶meters[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"); |
@@ -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)); | |||
@@ -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)); | |||
@@ -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)); | |||
@@ -15,14 +15,14 @@ struct LongPressButton { | |||
}; | |||
float pressedTime = 0.f; | |||
BooleanTrigger trigger; | |||
dsp::BooleanTrigger trigger; | |||
Events step(Param ¶m) { | |||
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)); | |||
@@ -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)); | |||
@@ -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)); | |||
@@ -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)); | |||
@@ -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)); | |||