| @@ -6,6 +6,7 @@ | |||
| "authorEmail": "contact@vcvrack.com", | |||
| "pluginUrl": "https://vcvrack.com/Fundamental.html", | |||
| "authorUrl": "https://vcvrack.com/", | |||
| "manualUrl": "https://vcvrack.com/Fundamental.html#manual", | |||
| "sourceUrl": "https://github.com/VCVRack/Fundamental", | |||
| "version": "1.0.0", | |||
| "modules": { | |||
| @@ -30,8 +30,8 @@ struct _8vert : Module { | |||
| float lastIn = 10.f; | |||
| for (int i = 0; i < 8; i++) { | |||
| lastIn = inputs[i].getNormalVoltage(lastIn); | |||
| float out = lastIn * params[i].value; | |||
| outputs[i].value = out; | |||
| float out = lastIn * params[i].getValue(); | |||
| outputs[i].setVoltage(out); | |||
| lights[2*i + 0].setSmoothBrightness(out / 5.f, args.sampleTime); | |||
| lights[2*i + 1].setSmoothBrightness(-out / 5.f, args.sampleTime); | |||
| } | |||
| @@ -43,14 +43,14 @@ struct ADSR : Module { | |||
| } | |||
| void process(const ProcessArgs &args) override { | |||
| float attack = clamp(params[ATTACK_PARAM].value + inputs[ATTACK_INPUT].value / 10.f, 0.f, 1.f); | |||
| float decay = clamp(params[DECAY_PARAM].value + inputs[DECAY_INPUT].value / 10.f, 0.f, 1.f); | |||
| float sustain = clamp(params[SUSTAIN_PARAM].value + inputs[SUSTAIN_INPUT].value / 10.f, 0.f, 1.f); | |||
| float release = clamp(params[RELEASE_PARAM].value + inputs[RELEASE_INPUT].value / 10.f, 0.f, 1.f); | |||
| float attack = clamp(params[ATTACK_PARAM].getValue() + inputs[ATTACK_INPUT].getVoltage() / 10.f, 0.f, 1.f); | |||
| float decay = clamp(params[DECAY_PARAM].getValue() + inputs[DECAY_INPUT].getVoltage() / 10.f, 0.f, 1.f); | |||
| float sustain = clamp(params[SUSTAIN_PARAM].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10.f, 0.f, 1.f); | |||
| float release = clamp(params[RELEASE_PARAM].getValue() + inputs[RELEASE_INPUT].getVoltage() / 10.f, 0.f, 1.f); | |||
| // Gate and trigger | |||
| bool gated = inputs[GATE_INPUT].value >= 1.f; | |||
| if (trigger.process(inputs[TRIG_INPUT].value)) | |||
| bool gated = inputs[GATE_INPUT].getVoltage() >= 1.f; | |||
| if (trigger.process(inputs[TRIG_INPUT].getVoltage())) | |||
| decaying = false; | |||
| const float base = 20000.f; | |||
| @@ -94,7 +94,7 @@ struct ADSR : Module { | |||
| bool sustaining = isNear(env, sustain, 1e-3); | |||
| bool resting = isNear(env, 0.f, 1e-3); | |||
| outputs[ENVELOPE_OUTPUT].value = 10.f * env; | |||
| outputs[ENVELOPE_OUTPUT].setVoltage(10.f * env); | |||
| // Lights | |||
| lights[ATTACK_LIGHT].value = (gated && !decaying) ? 1.f : 0.f; | |||
| @@ -49,12 +49,12 @@ struct Delay : Module { | |||
| void process(const ProcessArgs &args) override { | |||
| // Get input to delay block | |||
| float in = inputs[IN_INPUT].value; | |||
| float feedback = clamp(params[FEEDBACK_PARAM].value + inputs[FEEDBACK_INPUT].value / 10.0f, 0.0f, 1.0f); | |||
| float in = inputs[IN_INPUT].getVoltage(); | |||
| float feedback = clamp(params[FEEDBACK_PARAM].getValue() + inputs[FEEDBACK_INPUT].getVoltage() / 10.0f, 0.0f, 1.0f); | |||
| float dry = in + lastWet * feedback; | |||
| // Compute delay time in seconds | |||
| float delay = 1e-3 * std::pow(10.0f / 1e-3, clamp(params[TIME_PARAM].value + inputs[TIME_INPUT].value / 10.0f, 0.0f, 1.0f)); | |||
| float delay = 1e-3 * std::pow(10.0f / 1e-3, clamp(params[TIME_PARAM].getValue() + inputs[TIME_INPUT].getVoltage() / 10.0f, 0.0f, 1.0f)); | |||
| // Number of delay samples | |||
| float index = delay * args.sampleRate; | |||
| @@ -91,7 +91,7 @@ struct Delay : Module { | |||
| // Apply color to delay wet output | |||
| // TODO Make it sound better | |||
| float color = clamp(params[COLOR_PARAM].value + inputs[COLOR_INPUT].value / 10.0f, 0.0f, 1.0f); | |||
| float color = clamp(params[COLOR_PARAM].getValue() + inputs[COLOR_INPUT].getVoltage() / 10.0f, 0.0f, 1.0f); | |||
| float lowpassFreq = 10000.0f * std::pow(10.0f, clamp(2.0f*color, 0.0f, 1.0f)); | |||
| lowpassFilter.setCutoff(lowpassFreq / args.sampleRate); | |||
| lowpassFilter.process(wet); | |||
| @@ -103,9 +103,9 @@ struct Delay : Module { | |||
| lastWet = wet; | |||
| float mix = clamp(params[MIX_PARAM].value + inputs[MIX_INPUT].value / 10.0f, 0.0f, 1.0f); | |||
| float mix = clamp(params[MIX_PARAM].getValue() + inputs[MIX_INPUT].getVoltage() / 10.0f, 0.0f, 1.0f); | |||
| float out = crossfade(in, wet, mix); | |||
| outputs[OUT_OUTPUT].value = out; | |||
| outputs[OUT_OUTPUT].setVoltage(out); | |||
| } | |||
| }; | |||
| @@ -108,17 +108,17 @@ struct LFO : Module { | |||
| } | |||
| void process(const ProcessArgs &args) override { | |||
| oscillator.setPitch(params[FREQ_PARAM].value + params[FM1_PARAM].value * inputs[FM1_INPUT].value + params[FM2_PARAM].value * inputs[FM2_INPUT].value); | |||
| oscillator.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.f); | |||
| oscillator.offset = (params[OFFSET_PARAM].value > 0.f); | |||
| oscillator.invert = (params[INVERT_PARAM].value <= 0.f); | |||
| oscillator.setPitch(params[FREQ_PARAM].getValue() + params[FM1_PARAM].getValue() * inputs[FM1_INPUT].getVoltage() + params[FM2_PARAM].getValue() * inputs[FM2_INPUT].getVoltage()); | |||
| oscillator.setPulseWidth(params[PW_PARAM].getValue() + params[PWM_PARAM].getValue() * inputs[PW_INPUT].getVoltage() / 10.f); | |||
| oscillator.offset = (params[OFFSET_PARAM].getValue() > 0.f); | |||
| oscillator.invert = (params[INVERT_PARAM].getValue() <= 0.f); | |||
| oscillator.step(args.sampleTime); | |||
| oscillator.setReset(inputs[RESET_INPUT].value); | |||
| oscillator.setReset(inputs[RESET_INPUT].getVoltage()); | |||
| outputs[SIN_OUTPUT].value = 5.f * oscillator.sin(); | |||
| outputs[TRI_OUTPUT].value = 5.f * oscillator.tri(); | |||
| outputs[SAW_OUTPUT].value = 5.f * oscillator.saw(); | |||
| outputs[SQR_OUTPUT].value = 5.f * oscillator.sqr(); | |||
| outputs[SIN_OUTPUT].setVoltage(5.f * oscillator.sin()); | |||
| outputs[TRI_OUTPUT].setVoltage(5.f * oscillator.tri()); | |||
| outputs[SAW_OUTPUT].setVoltage(5.f * oscillator.saw()); | |||
| outputs[SQR_OUTPUT].setVoltage(5.f * oscillator.sqr()); | |||
| lights[PHASE_POS_LIGHT].setSmoothBrightness(oscillator.light(), args.sampleTime); | |||
| lights[PHASE_NEG_LIGHT].setSmoothBrightness(-oscillator.light(), args.sampleTime); | |||
| @@ -203,13 +203,13 @@ struct LFO2 : Module { | |||
| void process(const ProcessArgs &args) override { | |||
| float deltaTime = args.sampleTime; | |||
| oscillator.setPitch(params[FREQ_PARAM].value + params[FM_PARAM].value * inputs[FM_INPUT].value); | |||
| oscillator.offset = (params[OFFSET_PARAM].value > 0.f); | |||
| oscillator.invert = (params[INVERT_PARAM].value <= 0.f); | |||
| oscillator.setPitch(params[FREQ_PARAM].getValue() + params[FM_PARAM].getValue() * inputs[FM_INPUT].getVoltage()); | |||
| oscillator.offset = (params[OFFSET_PARAM].getValue() > 0.f); | |||
| oscillator.invert = (params[INVERT_PARAM].getValue() <= 0.f); | |||
| oscillator.step(deltaTime); | |||
| oscillator.setReset(inputs[RESET_INPUT].value); | |||
| oscillator.setReset(inputs[RESET_INPUT].getVoltage()); | |||
| float wave = params[WAVE_PARAM].value + inputs[WAVE_INPUT].value; | |||
| float wave = params[WAVE_PARAM].getValue() + inputs[WAVE_INPUT].getVoltage(); | |||
| wave = clamp(wave, 0.f, 3.f); | |||
| float interp; | |||
| if (wave < 1.f) | |||
| @@ -218,7 +218,7 @@ struct LFO2 : Module { | |||
| interp = crossfade(oscillator.tri(), oscillator.saw(), wave - 1.f); | |||
| else | |||
| interp = crossfade(oscillator.saw(), oscillator.sqr(), wave - 2.f); | |||
| outputs[INTERP_OUTPUT].value = 5.f * interp; | |||
| outputs[INTERP_OUTPUT].setVoltage(5.f * interp); | |||
| lights[PHASE_POS_LIGHT].setSmoothBrightness(oscillator.light(), deltaTime); | |||
| lights[PHASE_NEG_LIGHT].setSmoothBrightness(-oscillator.light(), deltaTime); | |||
| @@ -37,11 +37,11 @@ struct Mutes : Module { | |||
| void process(const ProcessArgs &args) override { | |||
| float out = 0.f; | |||
| for (int i = 0; i < NUM_CHANNELS; i++) { | |||
| if (muteTrigger[i].process(params[MUTE_PARAM + i].value)) | |||
| if (muteTrigger[i].process(params[MUTE_PARAM + i].getValue())) | |||
| state[i] ^= true; | |||
| if (inputs[IN_INPUT + i].active) | |||
| out = inputs[IN_INPUT + i].value; | |||
| outputs[OUT_OUTPUT + i].value = state[i] ? out : 0.f; | |||
| out = inputs[IN_INPUT + i].getVoltage(); | |||
| outputs[OUT_OUTPUT + i].setVoltage(state[i] ? out : 0.f); | |||
| lights[MUTE_LIGHT + i].setBrightness(state[i] ? 0.9f : 0.f); | |||
| } | |||
| } | |||
| @@ -110,7 +110,7 @@ struct SEQ3 : Module { | |||
| } | |||
| void setIndex(int index) { | |||
| int numSteps = (int) clamp(std::round(params[STEPS_PARAM].value + inputs[STEPS_INPUT].value), 1.0f, 8.0f); | |||
| int numSteps = (int) clamp(std::round(params[STEPS_PARAM].getValue() + inputs[STEPS_INPUT].getVoltage()), 1.0f, 8.0f); | |||
| phase = 0.f; | |||
| this->index = index; | |||
| if (this->index >= numSteps) | |||
| @@ -119,7 +119,7 @@ struct SEQ3 : Module { | |||
| void process(const ProcessArgs &args) override { | |||
| // Run | |||
| if (runningTrigger.process(params[RUN_PARAM].value)) { | |||
| if (runningTrigger.process(params[RUN_PARAM].getValue())) { | |||
| running = !running; | |||
| } | |||
| @@ -127,14 +127,14 @@ struct SEQ3 : Module { | |||
| if (running) { | |||
| if (inputs[EXT_CLOCK_INPUT].active) { | |||
| // External clock | |||
| if (clockTrigger.process(inputs[EXT_CLOCK_INPUT].value)) { | |||
| if (clockTrigger.process(inputs[EXT_CLOCK_INPUT].getVoltage())) { | |||
| setIndex(index + 1); | |||
| } | |||
| gateIn = clockTrigger.isHigh(); | |||
| } | |||
| else { | |||
| // Internal clock | |||
| float clockTime = std::pow(2.0f, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value); | |||
| float clockTime = std::pow(2.0f, params[CLOCK_PARAM].getValue() + inputs[CLOCK_INPUT].getVoltage()); | |||
| phase += clockTime * args.sampleTime; | |||
| if (phase >= 1.0f) { | |||
| setIndex(index + 1); | |||
| @@ -144,24 +144,24 @@ struct SEQ3 : Module { | |||
| } | |||
| // Reset | |||
| if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value)) { | |||
| if (resetTrigger.process(params[RESET_PARAM].getValue() + inputs[RESET_INPUT].getVoltage())) { | |||
| setIndex(0); | |||
| } | |||
| // Gate buttons | |||
| for (int i = 0; i < 8; i++) { | |||
| if (gateTriggers[i].process(params[GATE_PARAM + i].value)) { | |||
| if (gateTriggers[i].process(params[GATE_PARAM + i].getValue())) { | |||
| gates[i] = !gates[i]; | |||
| } | |||
| outputs[GATE_OUTPUT + i].value = (running && gateIn && i == index && gates[i]) ? 10.0f : 0.0f; | |||
| outputs[GATE_OUTPUT + i].setVoltage((running && gateIn && i == index && gates[i]) ? 10.0f : 0.0f); | |||
| lights[GATE_LIGHTS + i].setSmoothBrightness((gateIn && i == index) ? (gates[i] ? 1.f : 0.33) : (gates[i] ? 0.66 : 0.0), args.sampleTime); | |||
| } | |||
| // Outputs | |||
| outputs[ROW1_OUTPUT].value = params[ROW1_PARAM + index].value; | |||
| outputs[ROW2_OUTPUT].value = params[ROW2_PARAM + index].value; | |||
| outputs[ROW3_OUTPUT].value = params[ROW3_PARAM + index].value; | |||
| outputs[GATES_OUTPUT].value = (gateIn && gates[index]) ? 10.0f : 0.0f; | |||
| outputs[ROW1_OUTPUT].setVoltage(params[ROW1_PARAM + index].getValue()); | |||
| outputs[ROW2_OUTPUT].setVoltage(params[ROW2_PARAM + index].getValue()); | |||
| outputs[ROW3_OUTPUT].setVoltage(params[ROW3_PARAM + index].getValue()); | |||
| outputs[GATES_OUTPUT].setVoltage((gateIn && gates[index]) ? 10.0f : 0.0f); | |||
| lights[RUNNING_LIGHT].value = (running); | |||
| lights[RESET_LIGHT].setSmoothBrightness(resetTrigger.isHigh(), args.sampleTime); | |||
| lights[GATES_LIGHT].setSmoothBrightness(gateIn, args.sampleTime); | |||
| @@ -59,28 +59,28 @@ struct Scope : Module { | |||
| void process(const ProcessArgs &args) override { | |||
| // Modes | |||
| if (sumTrigger.process(params[LISSAJOUS_PARAM].value)) { | |||
| if (sumTrigger.process(params[LISSAJOUS_PARAM].getValue())) { | |||
| lissajous = !lissajous; | |||
| } | |||
| lights[PLOT_LIGHT].value = lissajous ? 0.0f : 1.0f; | |||
| lights[LISSAJOUS_LIGHT].value = lissajous ? 1.0f : 0.0f; | |||
| if (extTrigger.process(params[EXTERNAL_PARAM].value)) { | |||
| if (extTrigger.process(params[EXTERNAL_PARAM].getValue())) { | |||
| external = !external; | |||
| } | |||
| lights[INTERNAL_LIGHT].value = external ? 0.0f : 1.0f; | |||
| lights[EXTERNAL_LIGHT].value = external ? 1.0f : 0.0f; | |||
| // Compute time | |||
| float deltaTime = std::pow(2.0f, -params[TIME_PARAM].value); | |||
| float deltaTime = std::pow(2.0f, -params[TIME_PARAM].getValue()); | |||
| int frameCount = (int) std::ceil(deltaTime * args.sampleRate); | |||
| // Add frame to buffer | |||
| if (bufferIndex < BUFFER_SIZE) { | |||
| if (++frameIndex > frameCount) { | |||
| frameIndex = 0; | |||
| bufferX[bufferIndex] = inputs[X_INPUT].value; | |||
| bufferY[bufferIndex] = inputs[Y_INPUT].value; | |||
| bufferX[bufferIndex] = inputs[X_INPUT].getVoltage(); | |||
| bufferY[bufferIndex] = inputs[Y_INPUT].getVoltage(); | |||
| bufferIndex++; | |||
| } | |||
| } | |||
| @@ -101,11 +101,11 @@ struct Scope : Module { | |||
| frameIndex++; | |||
| // Must go below 0.1fV to trigger | |||
| float gate = external ? inputs[TRIG_INPUT].value : inputs[X_INPUT].value; | |||
| float gate = external ? inputs[TRIG_INPUT].getVoltage() : inputs[X_INPUT].getVoltage(); | |||
| // Reset if triggered | |||
| float holdTime = 0.1f; | |||
| if (resetTrigger.process(rescale(gate, params[TRIG_PARAM].value - 0.1f, params[TRIG_PARAM].value, 0.f, 1.f)) || (frameIndex >= args.sampleRate * holdTime)) { | |||
| if (resetTrigger.process(rescale(gate, params[TRIG_PARAM].getValue() - 0.1f, params[TRIG_PARAM].getValue(), 0.f, 1.f)) || (frameIndex >= args.sampleRate * holdTime)) { | |||
| bufferIndex = 0; frameIndex = 0; return; | |||
| } | |||
| @@ -260,10 +260,10 @@ struct ScopeDisplay : TransparentWidget { | |||
| if (!module) | |||
| return; | |||
| float gainX = std::pow(2.0f, std::round(module->params[Scope::X_SCALE_PARAM].value)); | |||
| float gainY = std::pow(2.0f, std::round(module->params[Scope::Y_SCALE_PARAM].value)); | |||
| float offsetX = module->params[Scope::X_POS_PARAM].value; | |||
| float offsetY = module->params[Scope::Y_POS_PARAM].value; | |||
| float gainX = std::pow(2.0f, std::round(module->params[Scope::X_SCALE_PARAM].getValue())); | |||
| float gainY = std::pow(2.0f, std::round(module->params[Scope::Y_SCALE_PARAM].getValue())); | |||
| float offsetX = module->params[Scope::X_POS_PARAM].getValue(); | |||
| float offsetY = module->params[Scope::Y_POS_PARAM].getValue(); | |||
| float valuesX[BUFFER_SIZE]; | |||
| float valuesY[BUFFER_SIZE]; | |||
| @@ -297,7 +297,7 @@ struct ScopeDisplay : TransparentWidget { | |||
| drawWaveform(args, valuesX, NULL); | |||
| } | |||
| float valueTrig = (module->params[Scope::TRIG_PARAM].value + offsetX) * gainX / 10.0f; | |||
| float valueTrig = (module->params[Scope::TRIG_PARAM].getValue() + offsetX) * gainX / 10.0f; | |||
| drawTrig(args, valueTrig); | |||
| } | |||
| @@ -1,7 +1,8 @@ | |||
| #include "plugin.hpp" | |||
| template <int TYPE> | |||
| // Only valid for <1, 4> and <4, 1> | |||
| template <int INPUTS, int OUTPUTS> | |||
| struct SequentialSwitch : Module { | |||
| enum ParamIds { | |||
| CHANNELS_PARAM, | |||
| @@ -10,11 +11,11 @@ struct SequentialSwitch : Module { | |||
| enum InputIds { | |||
| CLOCK_INPUT, | |||
| RESET_INPUT, | |||
| ENUMS(IN_INPUT, TYPE == 1 ? 1 : 4), | |||
| ENUMS(IN_INPUTS, INPUTS), | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| ENUMS(OUT_OUTPUT, TYPE == 1 ? 4 : 1), | |||
| ENUMS(OUT_OUTPUTS, OUTPUTS), | |||
| NUM_OUTPUTS | |||
| }; | |||
| enum LightIds { | |||
| @@ -25,61 +26,69 @@ struct SequentialSwitch : Module { | |||
| dsp::SchmittTrigger clockTrigger; | |||
| dsp::SchmittTrigger resetTrigger; | |||
| int channel = 0; | |||
| dsp::SlewLimiter channelFilter[4]; | |||
| dsp::Counter lightCounter; | |||
| dsp::SlewLimiter clickFilters[4]; | |||
| SequentialSwitch() { | |||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
| params[CHANNELS_PARAM].config(0.0, 2.0, 0.0, "Channels", "", 0.f, 1.f, 2.f); | |||
| params[CHANNELS_PARAM].config(0.0, 2.0, 0.0, "Channels", "", 0, -1, 4); | |||
| for (int i = 0; i < 4; i++) { | |||
| channelFilter[i].rise = 0.01f; | |||
| channelFilter[i].fall = 0.01f; | |||
| for (int i = 0; i < OUTPUTS; i++) { | |||
| clickFilters[i].rise = 400.f; // Hz | |||
| clickFilters[i].fall = 400.f; // Hz | |||
| } | |||
| lightCounter.setPeriod(512); | |||
| } | |||
| void process(const ProcessArgs &args) override { | |||
| // Determine current channel | |||
| if (clockTrigger.process(inputs[CLOCK_INPUT].value / 2.f)) { | |||
| if (clockTrigger.process(rescale(inputs[CLOCK_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) { | |||
| channel++; | |||
| } | |||
| if (resetTrigger.process(inputs[RESET_INPUT].value / 2.f)) { | |||
| if (resetTrigger.process(rescale(inputs[RESET_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) { | |||
| channel = 0; | |||
| } | |||
| int channels = 4 - (int) params[CHANNELS_PARAM].value; | |||
| channel %= channels; | |||
| int channels = 4 - (int) std::round(params[CHANNELS_PARAM].getValue()); | |||
| if (channel >= channels) | |||
| channel = 0; | |||
| // Filter channels | |||
| for (int i = 0; i < 4; i++) { | |||
| channelFilter[i].process(channel == i ? 1.f : 0.f); | |||
| // Get input | |||
| float v = 0.f; | |||
| if (INPUTS == 1) { | |||
| v = inputs[IN_INPUTS + 0].getVoltage(); | |||
| } | |||
| // Set outputs | |||
| if (TYPE == 1) { | |||
| float out = inputs[IN_INPUT + 0].value; | |||
| for (int i = 0; i < 4; i++) { | |||
| outputs[OUT_OUTPUT + i].value = channelFilter[i].out * out; | |||
| else { | |||
| for (int i = 0; i < INPUTS; i++) { | |||
| float in = inputs[IN_INPUTS + i].getVoltage(); | |||
| v += in * clickFilters[i].process(args.sampleTime, channel == i); | |||
| } | |||
| } | |||
| // Set output | |||
| if (OUTPUTS == 1) { | |||
| outputs[OUT_OUTPUTS + 0].setVoltage(v); | |||
| } | |||
| else { | |||
| float out = 0.f; | |||
| for (int i = 0; i < 4; i++) { | |||
| out += channelFilter[i].out * inputs[IN_INPUT + i].value; | |||
| for (int i = 0; i < OUTPUTS; i++) { | |||
| float out = v * clickFilters[i].process(args.sampleTime, channel == i); | |||
| outputs[OUT_OUTPUTS + i].setVoltage(out); | |||
| } | |||
| outputs[OUT_OUTPUT + 0].value = out; | |||
| } | |||
| // Set lights | |||
| for (int i = 0; i < 4; i++) { | |||
| lights[CHANNEL_LIGHT + i].setBrightness(channelFilter[i].out); | |||
| if (lightCounter.process()) { | |||
| for (int i = 0; i < 4; i++) { | |||
| lights[CHANNEL_LIGHT + i].setBrightness(channel == i); | |||
| } | |||
| } | |||
| } | |||
| }; | |||
| struct SequentialSwitch1Widget : ModuleWidget { | |||
| typedef SequentialSwitch<1> TSequentialSwitch; | |||
| typedef SequentialSwitch<1, 4> TSequentialSwitch; | |||
| SequentialSwitch1Widget(SequentialSwitch<1> *module) { | |||
| SequentialSwitch1Widget(TSequentialSwitch *module) { | |||
| setModule(module); | |||
| setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/SequentialSwitch1.svg"))); | |||
| @@ -90,12 +99,12 @@ struct SequentialSwitch1Widget : ModuleWidget { | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 17.694)), module, TSequentialSwitch::CLOCK_INPUT)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 32.1896)), module, TSequentialSwitch::RESET_INPUT)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51536, 62.8096)), module, TSequentialSwitch::IN_INPUT + 0)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51536, 62.8096)), module, TSequentialSwitch::IN_INPUTS + 0)); | |||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51536, 77.8095)), module, TSequentialSwitch::OUT_OUTPUT + 0)); | |||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 87.8113)), module, TSequentialSwitch::OUT_OUTPUT + 1)); | |||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 97.809)), module, TSequentialSwitch::OUT_OUTPUT + 2)); | |||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 107.809)), module, TSequentialSwitch::OUT_OUTPUT + 3)); | |||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51536, 77.8095)), module, TSequentialSwitch::OUT_OUTPUTS + 0)); | |||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 87.8113)), module, TSequentialSwitch::OUT_OUTPUTS + 1)); | |||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 97.809)), module, TSequentialSwitch::OUT_OUTPUTS + 2)); | |||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 107.809)), module, TSequentialSwitch::OUT_OUTPUTS + 3)); | |||
| addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.8203, 77.7158)), module, TSequentialSwitch::CHANNEL_LIGHT + 0)); | |||
| addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.8203, 87.7163)), module, TSequentialSwitch::CHANNEL_LIGHT + 1)); | |||
| @@ -105,13 +114,13 @@ struct SequentialSwitch1Widget : ModuleWidget { | |||
| }; | |||
| Model *modelSequentialSwitch1 = createModel<SequentialSwitch<1>, SequentialSwitch1Widget>("SequentialSwitch1"); | |||
| Model *modelSequentialSwitch1 = createModel<SequentialSwitch<1, 4>, SequentialSwitch1Widget>("SequentialSwitch1"); | |||
| struct SequentialSwitch2Widget : ModuleWidget { | |||
| typedef SequentialSwitch<2> TSequentialSwitch; | |||
| typedef SequentialSwitch<4, 1> TSequentialSwitch; | |||
| SequentialSwitch2Widget(SequentialSwitch<2> *module) { | |||
| SequentialSwitch2Widget(TSequentialSwitch *module) { | |||
| setModule(module); | |||
| setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/SequentialSwitch2.svg"))); | |||
| @@ -122,12 +131,12 @@ struct SequentialSwitch2Widget : ModuleWidget { | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 17.694)), module, TSequentialSwitch::CLOCK_INPUT)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 32.191)), module, TSequentialSwitch::RESET_INPUT)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 62.811)), module, TSequentialSwitch::IN_INPUT + 0)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 72.8114)), module, TSequentialSwitch::IN_INPUT + 1)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 82.8091)), module, TSequentialSwitch::IN_INPUT + 2)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 92.8109)), module, TSequentialSwitch::IN_INPUT + 3)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 62.811)), module, TSequentialSwitch::IN_INPUTS + 0)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 72.8114)), module, TSequentialSwitch::IN_INPUTS + 1)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 82.8091)), module, TSequentialSwitch::IN_INPUTS + 2)); | |||
| addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 92.8109)), module, TSequentialSwitch::IN_INPUTS + 3)); | |||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 107.622)), module, TSequentialSwitch::OUT_OUTPUT + 0)); | |||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 107.622)), module, TSequentialSwitch::OUT_OUTPUTS + 0)); | |||
| addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.7321, 62.6277)), module, TSequentialSwitch::CHANNEL_LIGHT + 0)); | |||
| addChild(createLight<TinyLight<GreenLight>>(mm2px(Vec(10.7321, 72.6281)), module, TSequentialSwitch::CHANNEL_LIGHT + 1)); | |||
| @@ -137,4 +146,4 @@ struct SequentialSwitch2Widget : ModuleWidget { | |||
| }; | |||
| Model *modelSequentialSwitch2 = createModel<SequentialSwitch<2>, SequentialSwitch2Widget>("SequentialSwitch2"); | |||
| Model *modelSequentialSwitch2 = createModel<SequentialSwitch<4, 1>, SequentialSwitch2Widget>("SequentialSwitch2"); | |||
| @@ -42,7 +42,7 @@ struct Unity : Module { | |||
| for (int i = 0; i < 2; i++) { | |||
| // Inputs | |||
| for (int j = 0; j < 6; j++) { | |||
| mix[i] += inputs[IN_INPUTS + 6 * i + j].value; | |||
| mix[i] += inputs[IN_INPUTS + 6 * i + j].getVoltage(); | |||
| if (inputs[IN_INPUTS + 6 * i + j].active) | |||
| count[i]++; | |||
| } | |||
| @@ -58,12 +58,12 @@ struct Unity : Module { | |||
| for (int i = 0; i < 2; i++) { | |||
| // Params | |||
| if (count[i] > 0 && (int) std::round(params[AVG1_PARAM + i].value) == 1) | |||
| if (count[i] > 0 && (int) std::round(params[AVG1_PARAM + i].getValue()) == 1) | |||
| mix[i] /= count[i]; | |||
| // Outputs | |||
| outputs[MIX1_OUTPUT + 2 * i].value = mix[i]; | |||
| outputs[INV1_OUTPUT + 2 * i].value = -mix[i]; | |||
| outputs[MIX1_OUTPUT + 2 * i].setVoltage(mix[i]); | |||
| outputs[INV1_OUTPUT + 2 * i].setVoltage(-mix[i]); | |||
| vuMeters[i].process(args.sampleTime, mix[i] / 10.f); | |||
| } | |||
| @@ -29,13 +29,13 @@ struct VCA : Module { | |||
| } | |||
| void stepChannel(InputIds in, ParamIds level, InputIds lin, InputIds exp, OutputIds out) { | |||
| float v = inputs[in].value * params[level].value; | |||
| float v = inputs[in].getVoltage() * params[level].getValue(); | |||
| if (inputs[lin].active) | |||
| v *= clamp(inputs[lin].value / 10.0f, 0.0f, 1.0f); | |||
| v *= clamp(inputs[lin].getVoltage() / 10.0f, 0.0f, 1.0f); | |||
| const float expBase = 50.0f; | |||
| if (inputs[exp].active) | |||
| v *= rescale(std::pow(expBase, clamp(inputs[exp].value / 10.0f, 0.0f, 1.0f)), 1.0f, expBase, 0.0f, 1.0f); | |||
| outputs[out].value = v; | |||
| v *= rescale(std::pow(expBase, clamp(inputs[exp].getVoltage() / 10.0f, 0.0f, 1.0f)), 1.0f, expBase, 0.0f, 1.0f); | |||
| outputs[out].setVoltage(v); | |||
| } | |||
| void process(const ProcessArgs &args) override { | |||
| @@ -104,10 +104,10 @@ struct VCA_1 : Module { | |||
| void process(const ProcessArgs &args) override { | |||
| float cv = inputs[CV_INPUT].getNormalVoltage(10.f) / 10.f; | |||
| if ((int) params[EXP_PARAM].value == 0) | |||
| if ((int) params[EXP_PARAM].getValue() == 0) | |||
| cv = std::pow(cv, 4.f); | |||
| lastCv = cv; | |||
| outputs[OUT_OUTPUT].value = inputs[IN_INPUT].value * params[LEVEL_PARAM].value * cv; | |||
| outputs[OUT_OUTPUT].setVoltage(inputs[IN_INPUT].getVoltage() * params[LEVEL_PARAM].getValue() * cv); | |||
| } | |||
| }; | |||
| @@ -93,13 +93,13 @@ struct VCF : Module { | |||
| void process(const ProcessArgs &args) override { | |||
| if (!outputs[LPF_OUTPUT].active && !outputs[HPF_OUTPUT].active) { | |||
| outputs[LPF_OUTPUT].value = 0.f; | |||
| outputs[HPF_OUTPUT].value = 0.f; | |||
| outputs[LPF_OUTPUT].setVoltage(0.f); | |||
| outputs[HPF_OUTPUT].setVoltage(0.f); | |||
| return; | |||
| } | |||
| float input = inputs[IN_INPUT].value / 5.f; | |||
| float drive = clamp(params[DRIVE_PARAM].value + inputs[DRIVE_INPUT].value / 10.f, 0.f, 1.f); | |||
| float input = inputs[IN_INPUT].getVoltage() / 5.f; | |||
| float drive = clamp(params[DRIVE_PARAM].getValue() + inputs[DRIVE_INPUT].getVoltage() / 10.f, 0.f, 1.f); | |||
| float gain = std::pow(1.f + drive, 5); | |||
| input *= gain; | |||
| @@ -107,15 +107,15 @@ struct VCF : Module { | |||
| input += 1e-6f * (2.f * random::uniform() - 1.f); | |||
| // Set resonance | |||
| float res = clamp(params[RES_PARAM].value + inputs[RES_INPUT].value / 10.f, 0.f, 1.f); | |||
| float res = clamp(params[RES_PARAM].getValue() + inputs[RES_INPUT].getVoltage() / 10.f, 0.f, 1.f); | |||
| filter.resonance = std::pow(res, 2) * 10.f; | |||
| // Set cutoff frequency | |||
| float pitch = 0.f; | |||
| if (inputs[FREQ_INPUT].active) | |||
| pitch += inputs[FREQ_INPUT].value * dsp::quadraticBipolar(params[FREQ_CV_PARAM].value); | |||
| pitch += params[FREQ_PARAM].value * 10.f - 5.f; | |||
| pitch += dsp::quadraticBipolar(params[FINE_PARAM].value * 2.f - 1.f) * 7.f / 12.f; | |||
| pitch += inputs[FREQ_INPUT].getVoltage() * dsp::quadraticBipolar(params[FREQ_CV_PARAM].getValue()); | |||
| pitch += params[FREQ_PARAM].getValue() * 10.f - 5.f; | |||
| pitch += dsp::quadraticBipolar(params[FINE_PARAM].getValue() * 2.f - 1.f) * 7.f / 12.f; | |||
| float cutoff = 261.626f * std::pow(2.f, pitch); | |||
| cutoff = clamp(cutoff, 1.f, 8000.f); | |||
| filter.setCutoff(cutoff); | |||
| @@ -136,15 +136,15 @@ struct VCF : Module { | |||
| // Set outputs | |||
| if (outputs[LPF_OUTPUT].active) { | |||
| outputs[LPF_OUTPUT].value = 5.f * lowpassDecimator.process(lowpassBuf); | |||
| outputs[LPF_OUTPUT].setVoltage(5.f * lowpassDecimator.process(lowpassBuf)); | |||
| } | |||
| if (outputs[HPF_OUTPUT].active) { | |||
| outputs[HPF_OUTPUT].value = 5.f * highpassDecimator.process(highpassBuf); | |||
| outputs[HPF_OUTPUT].setVoltage(5.f * highpassDecimator.process(highpassBuf)); | |||
| } | |||
| */ | |||
| filter.process(input, args.sampleTime); | |||
| outputs[LPF_OUTPUT].value = 5.f * filter.lowpass; | |||
| outputs[HPF_OUTPUT].value = 5.f * filter.highpass; | |||
| outputs[LPF_OUTPUT].setVoltage(5.f * filter.lowpass); | |||
| outputs[HPF_OUTPUT].setVoltage(5.f * filter.highpass); | |||
| } | |||
| }; | |||
| @@ -21,27 +21,27 @@ struct VCMixer : Module { | |||
| VCMixer() { | |||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | |||
| params[MIX_LVL_PARAM].config(0.0, 2.0, 1.0, "Master level"); | |||
| params[LVL_PARAM + 0].config(0.0, 1.0, 1.0, "Ch 1 level"); | |||
| params[LVL_PARAM + 1].config(0.0, 1.0, 1.0, "Ch 2 level"); | |||
| params[LVL_PARAM + 2].config(0.0, 1.0, 1.0, "Ch 3 level"); | |||
| params[LVL_PARAM + 3].config(0.0, 1.0, 1.0, "Ch 4 level"); | |||
| params[MIX_LVL_PARAM].config(0.0, 2.0, 1.0, "Master level", "%", 0, 100); | |||
| params[LVL_PARAM + 0].config(0.0, 1.0, 1.0, "Ch 1 level", "%", 0, 100); | |||
| params[LVL_PARAM + 1].config(0.0, 1.0, 1.0, "Ch 2 level", "%", 0, 100); | |||
| params[LVL_PARAM + 2].config(0.0, 1.0, 1.0, "Ch 3 level", "%", 0, 100); | |||
| params[LVL_PARAM + 3].config(0.0, 1.0, 1.0, "Ch 4 level", "%", 0, 100); | |||
| } | |||
| void process(const ProcessArgs &args) override { | |||
| float mix = 0.f; | |||
| for (int i = 0; i < 4; i++) { | |||
| float ch = inputs[CH_INPUT + i].value; | |||
| ch *= std::pow(params[LVL_PARAM + i].value, 2.f); | |||
| float ch = inputs[CH_INPUT + i].getVoltage(); | |||
| ch *= std::pow(params[LVL_PARAM + i].getValue(), 2.f); | |||
| if (inputs[CV_INPUT + i].active) | |||
| ch *= clamp(inputs[CV_INPUT + i].value / 10.f, 0.f, 1.f); | |||
| outputs[CH_OUTPUT + i].value = ch; | |||
| ch *= clamp(inputs[CV_INPUT + i].getVoltage() / 10.f, 0.f, 1.f); | |||
| outputs[CH_OUTPUT + i].setVoltage(ch); | |||
| mix += ch; | |||
| } | |||
| mix *= params[MIX_LVL_PARAM].value; | |||
| mix *= params[MIX_LVL_PARAM].getValue(); | |||
| if (inputs[MIX_CV_INPUT].active) | |||
| mix *= clamp(inputs[MIX_CV_INPUT].value / 10.f, 0.f, 1.f); | |||
| outputs[MIX_OUTPUT].value = mix; | |||
| mix *= clamp(inputs[MIX_CV_INPUT].getVoltage() / 10.f, 0.f, 1.f); | |||
| outputs[MIX_OUTPUT].setVoltage(mix); | |||
| } | |||
| }; | |||
| @@ -205,29 +205,29 @@ struct VCO : Module { | |||
| } | |||
| void process(const ProcessArgs &args) override { | |||
| oscillator.analog = params[MODE_PARAM].value > 0.f; | |||
| oscillator.soft = params[SYNC_PARAM].value <= 0.f; | |||
| oscillator.analog = params[MODE_PARAM].getValue() > 0.f; | |||
| oscillator.soft = params[SYNC_PARAM].getValue() <= 0.f; | |||
| float pitchFine = 3.f * dsp::quadraticBipolar(params[FINE_PARAM].value); | |||
| float pitchCv = 12.f * inputs[PITCH_INPUT].value; | |||
| float pitchFine = 3.f * dsp::quadraticBipolar(params[FINE_PARAM].getValue()); | |||
| float pitchCv = 12.f * inputs[PITCH_INPUT].getVoltage(); | |||
| if (inputs[FM_INPUT].active) { | |||
| pitchCv += dsp::quadraticBipolar(params[FM_PARAM].value) * 12.f * inputs[FM_INPUT].value; | |||
| pitchCv += dsp::quadraticBipolar(params[FM_PARAM].getValue()) * 12.f * inputs[FM_INPUT].getVoltage(); | |||
| } | |||
| oscillator.setPitch(params[FREQ_PARAM].value, pitchFine + pitchCv); | |||
| oscillator.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.f); | |||
| oscillator.setPitch(params[FREQ_PARAM].getValue(), pitchFine + pitchCv); | |||
| oscillator.setPulseWidth(params[PW_PARAM].getValue() + params[PWM_PARAM].getValue() * inputs[PW_INPUT].getVoltage() / 10.f); | |||
| oscillator.syncEnabled = inputs[SYNC_INPUT].active; | |||
| oscillator.process(args.sampleTime, inputs[SYNC_INPUT].value); | |||
| oscillator.process(args.sampleTime, inputs[SYNC_INPUT].getVoltage()); | |||
| // Set output | |||
| if (outputs[SIN_OUTPUT].active) | |||
| outputs[SIN_OUTPUT].value = 5.f * oscillator.sin(); | |||
| outputs[SIN_OUTPUT].setVoltage(5.f * oscillator.sin()); | |||
| if (outputs[TRI_OUTPUT].active) | |||
| outputs[TRI_OUTPUT].value = 5.f * oscillator.tri(); | |||
| outputs[TRI_OUTPUT].setVoltage(5.f * oscillator.tri()); | |||
| if (outputs[SAW_OUTPUT].active) | |||
| outputs[SAW_OUTPUT].value = 5.f * oscillator.saw(); | |||
| outputs[SAW_OUTPUT].setVoltage(5.f * oscillator.saw()); | |||
| if (outputs[SQR_OUTPUT].active) | |||
| outputs[SQR_OUTPUT].value = 5.f * oscillator.sqr(); | |||
| outputs[SQR_OUTPUT].setVoltage(5.f * oscillator.sqr()); | |||
| lights[PHASE_POS_LIGHT].setSmoothBrightness(oscillator.light(), args.sampleTime); | |||
| lights[PHASE_NEG_LIGHT].setSmoothBrightness(-oscillator.light(), args.sampleTime); | |||
| @@ -310,17 +310,17 @@ struct VCO2 : Module { | |||
| void process(const ProcessArgs &args) override { | |||
| float deltaTime = args.sampleTime; | |||
| oscillator.analog = params[MODE_PARAM].value > 0.f; | |||
| oscillator.soft = params[SYNC_PARAM].value <= 0.f; | |||
| oscillator.analog = params[MODE_PARAM].getValue() > 0.f; | |||
| oscillator.soft = params[SYNC_PARAM].getValue() <= 0.f; | |||
| float pitchCv = params[FREQ_PARAM].value + dsp::quadraticBipolar(params[FM_PARAM].value) * 12.f * inputs[FM_INPUT].value; | |||
| float pitchCv = params[FREQ_PARAM].getValue() + dsp::quadraticBipolar(params[FM_PARAM].getValue()) * 12.f * inputs[FM_INPUT].getVoltage(); | |||
| oscillator.setPitch(0.f, pitchCv); | |||
| oscillator.syncEnabled = inputs[SYNC_INPUT].active; | |||
| oscillator.process(deltaTime, inputs[SYNC_INPUT].value); | |||
| oscillator.process(deltaTime, inputs[SYNC_INPUT].getVoltage()); | |||
| // Set output | |||
| float wave = clamp(params[WAVE_PARAM].value + inputs[WAVE_INPUT].value, 0.f, 3.f); | |||
| float wave = clamp(params[WAVE_PARAM].getValue() + inputs[WAVE_INPUT].getVoltage(), 0.f, 3.f); | |||
| float out; | |||
| if (wave < 1.f) | |||
| out = crossfade(oscillator.sin(), oscillator.tri(), wave); | |||
| @@ -328,7 +328,7 @@ struct VCO2 : Module { | |||
| out = crossfade(oscillator.tri(), oscillator.saw(), wave - 1.f); | |||
| else | |||
| out = crossfade(oscillator.saw(), oscillator.sqr(), wave - 2.f); | |||
| outputs[OUT_OUTPUT].value = 5.f * out; | |||
| outputs[OUT_OUTPUT].setVoltage(5.f * out); | |||
| lights[PHASE_POS_LIGHT].setSmoothBrightness(oscillator.light(), deltaTime); | |||
| lights[PHASE_NEG_LIGHT].setSmoothBrightness(-oscillator.light(), deltaTime); | |||