| @@ -131,18 +131,18 @@ struct LFO : Module { | |||
| // FM1, polyphonic | |||
| pitch += float_4::load(inputs[FM1_INPUT].getVoltages(c)) * fm1Param; | |||
| // FM2, polyphonic or monophonic | |||
| if (inputs[FM2_INPUT].getChannels() == 1) | |||
| pitch += inputs[FM2_INPUT].getVoltage() * fm2Param; | |||
| else | |||
| if (inputs[FM2_INPUT].isPolyphonic()) | |||
| pitch += float_4::load(inputs[FM2_INPUT].getVoltages(c)) * fm2Param; | |||
| else | |||
| pitch += inputs[FM2_INPUT].getVoltage() * fm2Param; | |||
| oscillator->setPitch(pitch); | |||
| // Pulse width | |||
| float_4 pw = pwParam; | |||
| if (inputs[PW_INPUT].getChannels() == 1) | |||
| pw += inputs[PW_INPUT].getVoltage() / 10.f * pwmParam; | |||
| else | |||
| if (inputs[PW_INPUT].isPolyphonic()) | |||
| pw += float_4::load(inputs[PW_INPUT].getVoltages(c)) / 10.f * pwmParam; | |||
| else | |||
| pw += inputs[PW_INPUT].getVoltage() / 10.f * pwmParam; | |||
| oscillator->setPulseWidth(pw); | |||
| // Settings | |||
| @@ -284,10 +284,10 @@ struct LFO2 : Module { | |||
| // Wave | |||
| float_4 wave = waveParam; | |||
| inputs[WAVE_INPUT].getVoltage(); | |||
| if (inputs[WAVE_INPUT].getChannels() == 1) | |||
| wave += inputs[WAVE_INPUT].getVoltage() / 10.f * 3.f; | |||
| else | |||
| if (inputs[WAVE_INPUT].isPolyphonic()) | |||
| wave += float_4::load(inputs[WAVE_INPUT].getVoltages(c)) / 10.f * 3.f; | |||
| else | |||
| wave += inputs[WAVE_INPUT].getVoltage() / 10.f * 3.f; | |||
| wave = clamp(wave, 0.f, 3.f); | |||
| // Settings | |||
| @@ -42,7 +42,8 @@ struct Merge : Module { | |||
| outputs[POLY_OUTPUT].setVoltage(v, c); | |||
| } | |||
| outputs[POLY_OUTPUT].setChannels((channels >= 0) ? channels : (lastChannel + 1)); | |||
| // In order to allow 0 channels, modify channels directly instead of using `setChannels()` | |||
| outputs[POLY_OUTPUT].channels = (channels >= 0) ? channels : (lastChannel + 1); | |||
| // Set channel lights infrequently | |||
| if (lightDivider.process()) { | |||
| @@ -85,13 +85,13 @@ struct Scope : Module { | |||
| int frameCount = (int) std::ceil(deltaTime * args.sampleRate); | |||
| // Set channels | |||
| int channelsX = inputs[X_INPUT].isConnected() ? inputs[X_INPUT].getChannels() : 0; | |||
| int channelsX = inputs[X_INPUT].getChannels(); | |||
| if (channelsX != this->channelsX) { | |||
| std::memset(bufferX, 0, sizeof(bufferX)); | |||
| this->channelsX = channelsX; | |||
| } | |||
| int channelsY = inputs[Y_INPUT].isConnected() ? inputs[Y_INPUT].getChannels() : 0; | |||
| int channelsY = inputs[Y_INPUT].getChannels(); | |||
| if (channelsY != this->channelsY) { | |||
| std::memset(bufferY, 0, sizeof(bufferY)); | |||
| this->channelsY = channelsY; | |||
| @@ -28,7 +28,7 @@ struct Split : Module { | |||
| void process(const ProcessArgs &args) override { | |||
| for (int c = 0; c < 16; c++) { | |||
| float v = inputs[POLY_INPUT].getVoltage(c); | |||
| // To allow users to debug buggy modules, don't assume that undefined channels are 0V. | |||
| // To allow users to debug buggy modules, don't assume that undefined channel voltages are 0V. | |||
| outputs[MONO_OUTPUTS + c].setVoltage(v); | |||
| } | |||
| @@ -29,9 +29,6 @@ struct VCA : Module { | |||
| } | |||
| void processChannel(Input &in, Param &level, Input &lin, Input &exp, Output &out) { | |||
| if (!in.isConnected() || !out.isConnected()) | |||
| return; | |||
| // Get input | |||
| int channels = in.getChannels(); | |||
| simd::float_4 v[4]; | |||
| @@ -47,17 +44,17 @@ struct VCA : Module { | |||
| // Apply linear CV gain | |||
| if (lin.isConnected()) { | |||
| if (lin.getChannels() == 1) { | |||
| float cv = lin.getVoltage() / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| if (lin.isPolyphonic()) { | |||
| for (int c = 0; c < channels; c += 4) { | |||
| simd::float_4 cv = simd::float_4::load(lin.getVoltages(c)) / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| v[c / 4] *= cv; | |||
| } | |||
| } | |||
| else { | |||
| float cv = lin.getVoltage() / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| for (int c = 0; c < channels; c += 4) { | |||
| simd::float_4 cv = simd::float_4::load(lin.getVoltages(c)) / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| v[c / 4] *= cv; | |||
| } | |||
| } | |||
| @@ -66,19 +63,19 @@ struct VCA : Module { | |||
| // Apply exponential CV gain | |||
| const float expBase = 50.f; | |||
| if (exp.isConnected()) { | |||
| if (exp.getChannels() == 1) { | |||
| float cv = exp.getVoltage() / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| cv = rescale(std::pow(expBase, cv), 1.f, expBase, 0.f, 1.f); | |||
| if (exp.isPolyphonic()) { | |||
| for (int c = 0; c < channels; c += 4) { | |||
| simd::float_4 cv = simd::float_4::load(exp.getVoltages(c)) / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| cv = rescale(pow(expBase, cv), 1.f, expBase, 0.f, 1.f); | |||
| v[c / 4] *= cv; | |||
| } | |||
| } | |||
| else { | |||
| float cv = exp.getVoltage() / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| cv = rescale(std::pow(expBase, cv), 1.f, expBase, 0.f, 1.f); | |||
| for (int c = 0; c < channels; c += 4) { | |||
| simd::float_4 cv = simd::float_4::load(exp.getVoltages(c)) / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| cv = rescale(pow(expBase, cv), 1.f, expBase, 0.f, 1.f); | |||
| v[c / 4] *= cv; | |||
| } | |||
| } | |||
| @@ -128,12 +128,10 @@ struct VCF : Module { | |||
| // Drive gain | |||
| float_4 drive = driveParam; | |||
| if (inputs[DRIVE_INPUT].isConnected()) { | |||
| if (inputs[DRIVE_INPUT].isMonophonic()) | |||
| drive += inputs[DRIVE_INPUT].getVoltage() / 10.f; | |||
| else | |||
| drive += float_4::load(inputs[DRIVE_INPUT].getVoltages(c)) / 10.f; | |||
| } | |||
| if (inputs[DRIVE_INPUT].isPolyphonic()) | |||
| drive += float_4::load(inputs[DRIVE_INPUT].getVoltages(c)) / 10.f; | |||
| else | |||
| drive += inputs[DRIVE_INPUT].getVoltage() / 10.f; | |||
| drive = clamp(drive, 0.f, 1.f); | |||
| float_4 gain = simd::pow(1.f + drive, 5); | |||
| input *= gain; | |||
| @@ -143,23 +141,19 @@ struct VCF : Module { | |||
| // Set resonance | |||
| float_4 resonance = resParam; | |||
| if (inputs[RES_INPUT].isConnected()) { | |||
| if (inputs[RES_INPUT].isMonophonic()) | |||
| resonance += inputs[RES_INPUT].getVoltage() / 10.f; | |||
| else | |||
| resonance += float_4::load(inputs[RES_INPUT].getVoltages(c)) / 10.f; | |||
| } | |||
| if (inputs[RES_INPUT].isPolyphonic()) | |||
| resonance += float_4::load(inputs[RES_INPUT].getVoltages(c)) / 10.f; | |||
| else | |||
| resonance += inputs[RES_INPUT].getVoltage() / 10.f; | |||
| resonance = clamp(resonance, 0.f, 1.f); | |||
| filter->resonance = simd::pow(resonance, 2) * 10.f; | |||
| // Get pitch | |||
| float_4 pitch = 0.f; | |||
| if (inputs[FREQ_INPUT].isConnected()) { | |||
| if (inputs[FREQ_INPUT].isMonophonic()) | |||
| pitch += inputs[FREQ_INPUT].getVoltage() * freqCvParam; | |||
| else | |||
| pitch += float_4::load(inputs[FREQ_INPUT].getVoltages(c)) * freqCvParam; | |||
| } | |||
| if (inputs[FREQ_INPUT].isPolyphonic()) | |||
| pitch += float_4::load(inputs[FREQ_INPUT].getVoltages(c)) * freqCvParam; | |||
| else | |||
| pitch += inputs[FREQ_INPUT].getVoltage() * freqCvParam; | |||
| pitch += freqParam; | |||
| pitch += fineParam; | |||
| // Set cutoff | |||
| @@ -17,7 +17,7 @@ struct Viz : Module { | |||
| NUM_LIGHTS | |||
| }; | |||
| int lastChannels = 0; | |||
| int lastChannel = 0; | |||
| dsp::ClockDivider lightDivider; | |||
| Viz() { | |||
| @@ -27,7 +27,7 @@ struct Viz : Module { | |||
| void process(const ProcessArgs &args) override { | |||
| if (lightDivider.process()) { | |||
| lastChannels = inputs[POLY_INPUT].getChannels(); | |||
| lastChannel = inputs[POLY_INPUT].getChannels(); | |||
| float deltaTime = args.sampleTime * lightDivider.getDivision(); | |||
| for (int c = 0; c < 16; c++) { | |||
| @@ -58,7 +58,7 @@ struct VizDisplay : Widget { | |||
| nvgFontSize(args.vg, 11); | |||
| nvgTextLetterSpacing(args.vg, 0.0); | |||
| nvgTextAlign(args.vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); | |||
| if (module && c < module->lastChannels) | |||
| if (module && c < module->lastChannel) | |||
| nvgFillColor(args.vg, nvgRGB(255, 255, 255)); | |||
| else | |||
| nvgFillColor(args.vg, nvgRGB(99, 99, 99)); | |||