diff --git a/.github/workflows/build-plugin.yml b/.github/workflows/build-plugin.yml index d2c6638..15ee850 100644 --- a/.github/workflows/build-plugin.yml +++ b/.github/workflows/build-plugin.yml @@ -17,7 +17,7 @@ jobs: config: - { name: Linux, - os: ubuntu-latest, + os: ubuntu-16.04, prepare-os: sudo apt install -y libglu-dev } - { @@ -68,7 +68,7 @@ jobs: # only create a release if a tag was created that is called e.g. v1.2.3 # see also https://vcvrack.com/manual/Manifest#version if: startsWith(github.ref, 'refs/tags/v') - runs-on: ubuntu-latest + runs-on: ubuntu-16.04 needs: build steps: - uses: actions/checkout@v2 diff --git a/src/ABC.cpp b/src/ABC.cpp index 4f8dc04..9e2387d 100644 --- a/src/ABC.cpp +++ b/src/ABC.cpp @@ -1,6 +1,7 @@ #include "plugin.hpp" #include "Common.hpp" -#include "simd_input.hpp" + +using simd::float_4; template static T clip4(T x) { @@ -54,126 +55,112 @@ struct ABC : Module { configParam(C2_LEVEL_PARAM, -1.0, 1.0, 0.0, "C2 Level"); } - void process(const ProcessArgs &args) override { - - simd::float_4 a1[4] = {}; - simd::float_4 b1[4] = {}; - simd::float_4 c1[4] = {}; - simd::float_4 out1[4]; - - simd::float_4 a2[4] = {}; - simd::float_4 b2[4] = {}; - simd::float_4 c2[4] = {}; - simd::float_4 out2[4]; - - int channels_1 = 1; - int channels_2 = 1; - - memset(out1, 0, sizeof(out1)); - memset(out2, 0, sizeof(out2)); + int processSection(simd::float_4* out, InputIds inputA, InputIds inputB, InputIds inputC, + ParamIds levelB, ParamIds levelC) { - // process upper section - - if (outputs[OUT1_OUTPUT].isConnected() || outputs[OUT2_OUTPUT].isConnected()) { + float_4 inA[4] = {0.f}; + float_4 inB[4] = {0.f}; + float_4 inC[4] = {0.f}; - int channels_A1 = inputs[A1_INPUT].getChannels(); - int channels_B1 = inputs[B1_INPUT].getChannels(); - int channels_C1 = inputs[C1_INPUT].getChannels(); + int channelsA = inputs[inputA].getChannels(); + int channelsB = inputs[inputB].getChannels(); + int channelsC = inputs[inputC].getChannels(); - channels_1 = std::max(channels_1, channels_A1); - channels_1 = std::max(channels_1, channels_B1); - channels_1 = std::max(channels_1, channels_C1); + // this sets the number of active engines (according to polyphony standard) + // NOTE: A*B + C has the number of active engines set by any one of the three inputs + int activeEngines = std::max(1, channelsA); + activeEngines = std::max(activeEngines, channelsB); + activeEngines = std::max(activeEngines, channelsC); - float mult_B1 = (2.f / 5.f) * exponentialBipolar80Pade_5_4(params[B1_LEVEL_PARAM].getValue()); - float mult_C1 = exponentialBipolar80Pade_5_4(params[C1_LEVEL_PARAM].getValue()); + float mult_B = (2.f / 5.f) * exponentialBipolar80Pade_5_4(params[levelB].getValue()); + float mult_C = exponentialBipolar80Pade_5_4(params[levelC].getValue()); - if (inputs[A1_INPUT].isConnected()) - load_input(inputs[A1_INPUT], a1, channels_A1); - else - memset(a1, 0, sizeof(a1)); - - if (inputs[B1_INPUT].isConnected()) { - load_input(inputs[B1_INPUT], b1, channels_B1); - for (int c = 0; c < channels_1; c += 4) - b1[c / 4] *= simd::float_4(mult_B1); + if (inputs[inputA].isConnected()) { + // if monophonic, broadcast to number of active engines + if (channelsA == 1) { + for (int c = 0; c < activeEngines; c += 4) + inA[c / 4] = float_4(inputs[inputA].getVoltage()); } else { - for (int c = 0; c < channels_1; c += 4) - b1[c / 4] = simd::float_4(5.f * mult_B1); + for (int c = 0; c < channelsA; c += 4) + inA[c / 4] = inputs[inputA].getVoltageSimd(c); } + } - if (inputs[C1_INPUT].isConnected()) { - load_input(inputs[C1_INPUT], c1, channels_C1); - for (int c = 0; c < channels_1; c += 4) - c1[c / 4] *= simd::float_4(mult_C1); + if (inputs[inputB].isConnected()) { + // if monophonic, broadcast to number of active engines + if (channelsB == 1) { + for (int c = 0; c < activeEngines; c += 4) + inB[c / 4] = float_4(inputs[inputB].getVoltage()); } else { - for (int c = 0; c < channels_1; c += 4) - c1[c / 4] = simd::float_4(10.f * mult_C1); + for (int c = 0; c < channelsB; c += 4) + inB[c / 4] = inputs[inputB].getVoltageSimd(c); } - - for (int c = 0; c < channels_1; c += 4) - out1[c / 4] = clip4(a1[c / 4] * b1[c / 4] + c1[c / 4]); + for (int c = 0; c < activeEngines; c += 4) + inB[c / 4] *= mult_B; + } + else { + for (int c = 0; c < activeEngines; c += 4) + inB[c / 4] = 5.f * mult_B; } - // process lower section - - if (outputs[OUT2_OUTPUT].isConnected()) { - int channels_A2 = inputs[A2_INPUT].getChannels(); - int channels_B2 = inputs[B2_INPUT].getChannels(); - int channels_C2 = inputs[C2_INPUT].getChannels(); - - channels_2 = std::max(channels_2, channels_A2); - channels_2 = std::max(channels_2, channels_B2); - channels_2 = std::max(channels_2, channels_C2); - - float mult_B2 = (2.f / 5.f) * exponentialBipolar80Pade_5_4(params[B2_LEVEL_PARAM].getValue()); - float mult_C2 = exponentialBipolar80Pade_5_4(params[C2_LEVEL_PARAM].getValue()); - - if (inputs[A2_INPUT].isConnected()) - load_input(inputs[A2_INPUT], a2, channels_A2); - else - memset(a2, 0, sizeof(a2)); - - if (inputs[B2_INPUT].isConnected()) { - load_input(inputs[B2_INPUT], b2, channels_B2); - for (int c = 0; c < channels_2; c += 4) - b2[c / 4] *= simd::float_4(mult_B2); + if (inputs[inputC].isConnected()) { + // if monophonic, broadcast to number of active engines + if (channelsC == 1) { + for (int c = 0; c < activeEngines; c += 4) + inC[c / 4] = float_4(inputs[inputC].getVoltage()); } else { - for (int c = 0; c < channels_2; c += 4) - b2[c / 4] = simd::float_4(5.f * mult_B2); + for (int c = 0; c < channelsC; c += 4) + inC[c / 4] = inputs[inputC].getVoltageSimd(c); } - if (inputs[C2_INPUT].isConnected()) { - load_input(inputs[C2_INPUT], c2, channels_C2); - for (int c = 0; c < channels_2; c += 4) - c2[c / 4] *= simd::float_4(mult_C2); - } - else { - for (int c = 0; c < channels_2; c += 4) - c2[c / 4] = simd::float_4(10.f * mult_C2); - } + for (int c = 0; c < activeEngines; c += 4) + inC[c / 4] *= mult_C; + } + else { + for (int c = 0; c < activeEngines; c += 4) + inC[c / 4] = float_4(10.f * mult_C); + } + + for (int c = 0; c < activeEngines; c += 4) + out[c / 4] = clip4(inA[c / 4] * inB[c / 4] + inC[c / 4]); + + return activeEngines; + } + + void process(const ProcessArgs& args) override { - for (int c = 0; c < channels_2; c += 4) - out2[c / 4] = clip4(a2[c / 4] * b2[c / 4] + c2[c / 4]); - }; + // process upper section + float_4 out1[4] = {0.f}; + int activeEngines1 = 1; + if (outputs[OUT1_OUTPUT].isConnected() || outputs[OUT2_OUTPUT].isConnected()) { + activeEngines1 = processSection(out1, A1_INPUT, B1_INPUT, C1_INPUT, B1_LEVEL_PARAM, C1_LEVEL_PARAM); + } + + float_4 out2[4] = {0.f}; + int activeEngines2 = 1; + // process lower section + if (outputs[OUT2_OUTPUT].isConnected()) { + activeEngines2 = processSection(out2, A2_INPUT, B2_INPUT, C2_INPUT, B2_LEVEL_PARAM, C2_LEVEL_PARAM); + } // Set outputs if (outputs[OUT1_OUTPUT].isConnected()) { - outputs[OUT1_OUTPUT].setChannels(channels_1); - for (int c = 0; c < channels_1; c += 4) + outputs[OUT1_OUTPUT].setChannels(activeEngines1); + for (int c = 0; c < activeEngines1; c += 4) out1[c / 4].store(outputs[OUT1_OUTPUT].getVoltages(c)); } - else { - for (int c = 0; c < channels_1; c += 4) + else if (outputs[OUT2_OUTPUT].isConnected()) { + + for (int c = 0; c < activeEngines1; c += 4) out2[c / 4] += out1[c / 4]; - channels_2 = std::max(channels_1, channels_2); - } - if (outputs[OUT2_OUTPUT].isConnected()) { - outputs[OUT2_OUTPUT].setChannels(channels_2); - for (int c = 0; c < channels_2; c += 4) + activeEngines2 = std::max(activeEngines1, activeEngines2); + + outputs[OUT2_OUTPUT].setChannels(activeEngines2); + for (int c = 0; c < activeEngines2; c += 4) out2[c / 4].store(outputs[OUT2_OUTPUT].getVoltages(c)); } @@ -182,7 +169,7 @@ struct ABC : Module { float light_1; float light_2; - if (channels_1 == 1) { + if (activeEngines1 == 1) { light_1 = out1[0].s[0]; lights[OUT1_LIGHT + 0].setSmoothBrightness(light_1 / 5.f, args.sampleTime); lights[OUT1_LIGHT + 1].setSmoothBrightness(-light_1 / 5.f, args.sampleTime); @@ -195,7 +182,7 @@ struct ABC : Module { lights[OUT1_LIGHT + 2].setBrightness(light_1); } - if (channels_2 == 1) { + if (activeEngines2 == 1) { light_2 = out2[0].s[0]; lights[OUT2_LIGHT + 0].setSmoothBrightness(light_2 / 5.f, args.sampleTime); lights[OUT2_LIGHT + 1].setSmoothBrightness(-light_2 / 5.f, args.sampleTime); @@ -212,7 +199,7 @@ struct ABC : Module { struct ABCWidget : ModuleWidget { - ABCWidget(ABC *module) { + ABCWidget(ABC* module) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ABC.svg"))); @@ -239,4 +226,4 @@ struct ABCWidget : ModuleWidget { }; -Model *modelABC = createModel("ABC"); +Model* modelABC = createModel("ABC"); diff --git a/src/DualAtenuverter.cpp b/src/DualAtenuverter.cpp index e24e2fd..b32fbb4 100644 --- a/src/DualAtenuverter.cpp +++ b/src/DualAtenuverter.cpp @@ -1,6 +1,5 @@ #include "plugin.hpp" #include "Common.hpp" -#include "simd_input.hpp" struct DualAtenuverter : Module { enum ParamIds { @@ -34,7 +33,7 @@ struct DualAtenuverter : Module { configParam(OFFSET2_PARAM, -10.0, 10.0, 0.0, "Ch 2 offset", " V"); } - void process(const ProcessArgs &args) override { + void process(const ProcessArgs& args) override { using simd::float_4; float_4 out1[4]; @@ -52,10 +51,10 @@ struct DualAtenuverter : Module { float offset2 = params[OFFSET2_PARAM].getValue(); for (int c = 0; c < channels1; c += 4) { - out1[c / 4] = clamp(float_4::load(inputs[IN1_INPUT].getVoltages(c)) * att1 + offset1, -10.f, 10.f); + out1[c / 4] = clamp(inputs[IN1_INPUT].getVoltageSimd(c) * att1 + offset1, -10.f, 10.f); } for (int c = 0; c < channels2; c += 4) { - out2[c / 4] = clamp(float_4::load(inputs[IN2_INPUT].getVoltages(c)) * att2 + offset2, -10.f, 10.f); + out2[c / 4] = clamp(inputs[IN2_INPUT].getVoltageSimd(c) * att2 + offset2, -10.f, 10.f); } outputs[OUT1_OUTPUT].setChannels(channels1); @@ -97,7 +96,7 @@ struct DualAtenuverter : Module { struct DualAtenuverterWidget : ModuleWidget { - DualAtenuverterWidget(DualAtenuverter *module) { + DualAtenuverterWidget(DualAtenuverter* module) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/DualAtenuverter.svg"))); @@ -121,4 +120,4 @@ struct DualAtenuverterWidget : ModuleWidget { }; -Model *modelDualAtenuverter = createModel("DualAtenuverter"); +Model* modelDualAtenuverter = createModel("DualAtenuverter"); \ No newline at end of file diff --git a/src/EvenVCO.cpp b/src/EvenVCO.cpp index ec69ea7..ec708b3 100644 --- a/src/EvenVCO.cpp +++ b/src/EvenVCO.cpp @@ -1,7 +1,8 @@ #include "plugin.hpp" -#include "simd_input.hpp" #include "Common.hpp" +using simd::float_4; + struct EvenVCO : Module { enum ParamIds { OCTAVE_PARAM, @@ -26,8 +27,8 @@ struct EvenVCO : Module { NUM_OUTPUTS }; - simd::float_4 phase[4]; - simd::float_4 tri[4]; + float_4 phase[4]; + float_4 tri[4]; /** The value of the last sync input */ float sync = 0.0; @@ -51,23 +52,14 @@ struct EvenVCO : Module { configParam(PWM_PARAM, -1.0, 1.0, 0.0, "Pulse width"); for (int i = 0; i < 4; i++) { - phase[i] = simd::float_4(0.0f); - tri[i] = simd::float_4(0.0f); + phase[i] = float_4(0.0f); + tri[i] = float_4(0.0f); } for (int c = 0; c < PORT_MAX_CHANNELS; c++) halfPhase[c] = false; } - void process(const ProcessArgs &args) override { - simd::float_4 pitch[4]; - simd::float_4 pitch_1[4]; - simd::float_4 pitch_2[4]; - simd::float_4 pitch_fm[4]; - simd::float_4 freq[4]; - simd::float_4 pw[4]; - simd::float_4 pwm[4]; - simd::float_4 deltaPhase[4]; - simd::float_4 oldPhase[4]; + void process(const ProcessArgs& args) override { int channels_pitch1 = inputs[PITCH1_INPUT].getChannels(); int channels_pitch2 = inputs[PITCH2_INPUT].getChannels(); @@ -81,56 +73,79 @@ struct EvenVCO : Module { float pitch_0 = 1.f + std::round(params[OCTAVE_PARAM].getValue()) + params[TUNE_PARAM].getValue() / 12.f; // Compute frequency, pitch is 1V/oct - + float_4 pitch[4]; for (int c = 0; c < channels; c += 4) - pitch[c / 4] = simd::float_4(pitch_0); + pitch[c / 4] = float_4(pitch_0); if (inputs[PITCH1_INPUT].isConnected()) { - load_input(inputs[PITCH1_INPUT], pitch_1, channels_pitch1); - for (int c = 0; c < channels_pitch1; c += 4) - pitch[c / 4] += pitch_1[c / 4]; + // if pitch_1 monophonic, broadcast + if (channels_pitch1 == 1) { + for (int c = 0; c < channels; c += 4) + pitch[c / 4] += float_4(inputs[PITCH1_INPUT].getVoltage()); + } + else { + for (int c = 0; c < std::min(channels, channels_pitch1); c += 4) + pitch[c / 4] += inputs[PITCH1_INPUT].getVoltageSimd(c); + } } if (inputs[PITCH2_INPUT].isConnected()) { - load_input(inputs[PITCH2_INPUT], pitch_2, channels_pitch2); - for (int c = 0; c < channels_pitch2; c += 4) - pitch[c / 4] += pitch_2[c / 4]; + // if pitch_2 monophonic, broadcast + if (channels_pitch2 == 1) { + for (int c = 0; c < channels; c += 4) + pitch[c / 4] += float_4(inputs[PITCH2_INPUT].getVoltage()); + } + else { + for (int c = 0; c < std::min(channels, channels_pitch2); c += 4) + pitch[c / 4] += inputs[PITCH2_INPUT].getVoltageSimd(c); + } } if (inputs[FM_INPUT].isConnected()) { - load_input(inputs[FM_INPUT], pitch_fm, channels_fm); - for (int c = 0; c < channels_fm; c += 4) - pitch[c / 4] += pitch_fm[c / 4] / 4.f; + // if FM is monophonic, broadcast + if (channels_fm == 1) { + for (int c = 0; c < channels; c += 4) + pitch[c / 4] += float_4(inputs[FM_INPUT].getVoltage() / 4.f); + } + else { + for (int c = 0; c < std::min(channels, channels_fm); c += 4) + pitch[c / 4] += inputs[FM_INPUT].getVoltageSimd(c) / 4.f; + } } + float_4 freq[4]; for (int c = 0; c < channels; c += 4) { freq[c / 4] = dsp::FREQ_C4 * simd::pow(2.f, pitch[c / 4]); freq[c / 4] = clamp(freq[c / 4], 0.f, 20000.f); } - // Pulse width - float pw_0 = params[PWM_PARAM].getValue(); - + float_4 pw[4]; for (int c = 0; c < channels; c += 4) - pw[c / 4] = simd::float_4(pw_0); + pw[c / 4] = float_4(pw_0); if (inputs[PWM_INPUT].isConnected()) { - load_input(inputs[PWM_INPUT], pwm, channels_pwm); - for (int c = 0; c < channels_pwm; c += 4) - pw[c / 4] += pwm[c / 4] / 5.f; + if (channels_pwm == 1) { + for (int c = 0; c < channels; c += 4) + pw[c / 4] += float_4(inputs[PWM_INPUT].getVoltage() / 5.f); + } + else { + for (int c = 0; c < std::min(channels, channels_pwm); c += 4) + pw[c / 4] += inputs[PWM_INPUT].getVoltageSimd(c) / 5.f; + } } - const simd::float_4 minPw_4 = simd::float_4(0.05f); - const simd::float_4 m_one_4 = simd::float_4(-1.0f); - const simd::float_4 one_4 = simd::float_4(1.0f); - + const float_4 minPw_4 = float_4(0.05f); + const float_4 m_one_4 = float_4(-1.0f); + const float_4 one_4 = float_4(1.0f); + float_4 deltaPhase[4]; + float_4 oldPhase[4]; for (int c = 0; c < channels; c += 4) { pw[c / 4] = rescale(clamp(pw[c / 4], m_one_4, one_4), m_one_4, one_4, minPw_4, one_4 - minPw_4); // Advance phase - deltaPhase[c / 4] = clamp(freq[c / 4] * args.sampleTime, simd::float_4(1e-6f), simd::float_4(0.5f)); + deltaPhase[c / 4] = clamp(freq[c / 4] * args.sampleTime, float_4(1e-6f), float_4(0.5f)); oldPhase[c / 4] = phase[c / 4]; phase[c / 4] += deltaPhase[c / 4]; } @@ -163,19 +178,19 @@ struct EvenVCO : Module { } } - simd::float_4 triSquareMinBlepOut[4]; - simd::float_4 doubleSawMinBlepOut[4]; - simd::float_4 sawMinBlepOut[4]; - simd::float_4 squareMinBlepOut[4]; + float_4 triSquareMinBlepOut[4]; + float_4 doubleSawMinBlepOut[4]; + float_4 sawMinBlepOut[4]; + float_4 squareMinBlepOut[4]; - simd::float_4 triSquare[4]; - simd::float_4 sine[4]; - simd::float_4 doubleSaw[4]; + float_4 triSquare[4]; + float_4 sine[4]; + float_4 doubleSaw[4]; - simd::float_4 even[4]; - simd::float_4 saw[4]; - simd::float_4 square[4]; - simd::float_4 triOut[4]; + float_4 even[4]; + float_4 saw[4]; + float_4 square[4]; + float_4 triOut[4]; for (int c = 0; c < channels; c++) { triSquareMinBlepOut[c / 4].s[c % 4] = triSquareMinBlep[c].process(); @@ -231,7 +246,7 @@ struct EvenVCO : Module { struct EvenVCOWidget : ModuleWidget { - EvenVCOWidget(EvenVCO *module) { + EvenVCOWidget(EvenVCO* module) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/EvenVCO.svg"))); @@ -260,4 +275,4 @@ struct EvenVCOWidget : ModuleWidget { }; -Model *modelEvenVCO = createModel("EvenVCO"); +Model* modelEvenVCO = createModel("EvenVCO"); diff --git a/src/Mixer.cpp b/src/Mixer.cpp index 8ea8c2c..f8e96ff 100644 --- a/src/Mixer.cpp +++ b/src/Mixer.cpp @@ -1,6 +1,7 @@ #include "plugin.hpp" #include "Common.hpp" -#include "simd_input.hpp" + +using simd::float_4; struct Mixer : Module { enum ParamIds { @@ -37,7 +38,7 @@ struct Mixer : Module { configParam(CH4_PARAM, 0.0, 1.0, 0.0, "Ch 4 level", "%", 0, 100); } - void process(const ProcessArgs &args) override { + void process(const ProcessArgs& args) override { int channels1 = inputs[IN1_INPUT].getChannels(); int channels2 = inputs[IN2_INPUT].getChannels(); int channels3 = inputs[IN3_INPUT].getChannels(); @@ -49,37 +50,35 @@ struct Mixer : Module { out_channels = std::max(out_channels, channels3); out_channels = std::max(out_channels, channels4); - simd::float_4 mult1 = simd::float_4(params[CH1_PARAM].getValue()); - simd::float_4 mult2 = simd::float_4(params[CH2_PARAM].getValue()); - simd::float_4 mult3 = simd::float_4(params[CH3_PARAM].getValue()); - simd::float_4 mult4 = simd::float_4(params[CH4_PARAM].getValue()); + float_4 mult1 = float_4(params[CH1_PARAM].getValue()); + float_4 mult2 = float_4(params[CH2_PARAM].getValue()); + float_4 mult3 = float_4(params[CH3_PARAM].getValue()); + float_4 mult4 = float_4(params[CH4_PARAM].getValue()); - simd::float_4 out[4]; + float_4 out[4]; std::memset(out, 0, sizeof(out)); - if (inputs[IN1_INPUT].isConnected()) { for (int c = 0; c < channels1; c += 4) - out[c / 4] += simd::float_4::load(inputs[IN1_INPUT].getVoltages(c)) * mult1; + out[c / 4] += inputs[IN1_INPUT].getVoltageSimd(c) * mult1; } if (inputs[IN2_INPUT].isConnected()) { for (int c = 0; c < channels2; c += 4) - out[c / 4] += simd::float_4::load(inputs[IN2_INPUT].getVoltages(c)) * mult2; + out[c / 4] += inputs[IN2_INPUT].getVoltageSimd(c) * mult2; } if (inputs[IN3_INPUT].isConnected()) { for (int c = 0; c < channels3; c += 4) - out[c / 4] += simd::float_4::load(inputs[IN3_INPUT].getVoltages(c)) * mult3; + out[c / 4] += inputs[IN3_INPUT].getVoltageSimd(c) * mult3; } if (inputs[IN4_INPUT].isConnected()) { for (int c = 0; c < channels4; c += 4) - out[c / 4] += simd::float_4::load(inputs[IN4_INPUT].getVoltages(c)) * mult4; + out[c / 4] += inputs[IN4_INPUT].getVoltageSimd(c) * mult4; } - outputs[OUT1_OUTPUT].setChannels(out_channels); outputs[OUT2_OUTPUT].setChannels(out_channels); @@ -105,13 +104,12 @@ struct Mixer : Module { lights[OUT_NEG_LIGHT].setBrightness(0.0f); lights[OUT_BLUE_LIGHT].setSmoothBrightness(light / 5.f, args.sampleTime); } - } }; struct MixerWidget : ModuleWidget { - MixerWidget(Mixer *module) { + MixerWidget(Mixer* module) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Mixer.svg"))); @@ -137,4 +135,4 @@ struct MixerWidget : ModuleWidget { }; -Model *modelMixer = createModel("Mixer"); +Model* modelMixer = createModel("Mixer"); diff --git a/src/Rampage.cpp b/src/Rampage.cpp index 0a4d7df..c4061c2 100644 --- a/src/Rampage.cpp +++ b/src/Rampage.cpp @@ -1,16 +1,17 @@ #include "plugin.hpp" #include "Common.hpp" -#include "simd_input.hpp" #include "PulseGenerator_4.hpp" -static simd::float_4 shapeDelta(simd::float_4 delta, simd::float_4 tau, float shape) { - simd::float_4 lin = simd::sgn(delta) * 10.f / tau; +using simd::float_4; + +static float_4 shapeDelta(float_4 delta, float_4 tau, float shape) { + float_4 lin = simd::sgn(delta) * 10.f / tau; if (shape < 0.f) { - simd::float_4 log = simd::sgn(delta) * simd::float_4(40.f) / tau / (simd::fabs(delta) + simd::float_4(1.f)); + float_4 log = simd::sgn(delta) * float_4(40.f) / tau / (simd::fabs(delta) + float_4(1.f)); return simd::crossfade(lin, log, -shape * 0.95f); } else { - simd::float_4 exp = M_E * delta / tau; + float_4 exp = M_E * delta / tau; return simd::crossfade(lin, exp, shape * 0.90f); } } @@ -75,10 +76,10 @@ struct Rampage : Module { }; - simd::float_4 out[2][4]; - simd::float_4 gate[2][4]; // use simd __m128 logic instead of bool + float_4 out[2][4]; + float_4 gate[2][4]; // use simd __m128 logic instead of bool - dsp::TSchmittTrigger trigger_4[2][4]; + dsp::TSchmittTrigger trigger_4[2][4]; PulseGenerator_4 endOfCyclePulse[2][4]; // ChannelMask channelMask; @@ -103,10 +104,10 @@ struct Rampage : Module { std::memset(gate, 0, sizeof(gate)); } - void process(const ProcessArgs &args) override { + void process(const ProcessArgs& args) override { int channels_in[2]; int channels_trig[2]; - int channels[2]; + int channels[2]; // the larger of in or trig (per-part) // determine number of channels: @@ -122,25 +123,25 @@ struct Rampage : Module { outputs[FALLING_A_OUTPUT + part].setChannels(channels[part]); outputs[EOC_A_OUTPUT + part].setChannels(channels[part]); } - int channels_max = std::max(channels[0], channels[1]); + + // total number of active polyphony engines, accounting for both halves + // (channels[0] / channels[1] are the number of active engines per section) + const int channels_max = std::max(channels[0], channels[1]); outputs[COMPARATOR_OUTPUT].setChannels(channels_max); outputs[MIN_OUTPUT].setChannels(channels_max); outputs[MAX_OUTPUT].setChannels(channels_max); // loop over two parts of Rampage: - for (int part = 0; part < 2; part++) { - simd::float_4 in[4]; - simd::float_4 in_trig[4]; - simd::float_4 expCV[4]; - simd::float_4 riseCV[4]; - simd::float_4 fallCV[4]; - simd::float_4 cycle[4]; + float_4 in[4]; + float_4 in_trig[4]; + float_4 riseCV[4]; + float_4 fallCV[4]; + float_4 cycle[4]; // get parameters: - float shape = params[SHAPE_A_PARAM + part].getValue(); float minTime; switch ((int) params[RANGE_A_PARAM + part].getValue()) { @@ -155,91 +156,142 @@ struct Rampage : Module { break; } - simd::float_4 param_rise = simd::float_4(params[RISE_A_PARAM + part].getValue() * 10.0f); - simd::float_4 param_fall = simd::float_4(params[FALL_A_PARAM + part].getValue() * 10.0f); - simd::float_4 param_trig = simd::float_4(params[TRIGG_A_PARAM + part].getValue() * 20.0f); - simd::float_4 param_cycle = simd::float_4(params[CYCLE_A_PARAM + part].getValue() * 10.0f); + float_4 param_rise = float_4(params[RISE_A_PARAM + part].getValue() * 10.0f); + float_4 param_fall = float_4(params[FALL_A_PARAM + part].getValue() * 10.0f); + float_4 param_trig = float_4(params[TRIGG_A_PARAM + part].getValue() * 20.0f); + float_4 param_cycle = float_4(params[CYCLE_A_PARAM + part].getValue() * 10.0f); for (int c = 0; c < channels[part]; c += 4) { riseCV[c / 4] = param_rise; fallCV[c / 4] = param_fall; cycle[c / 4] = param_cycle; in_trig[c / 4] = param_trig; - } - // read inputs: - if (inputs[IN_A_INPUT + part].isConnected()) { - load_input(inputs[IN_A_INPUT + part], in, channels_in[part]); - // channelMask.apply_all(in, channels_in[part]); + // if IN__INPUT is monophonic, broadcast to the active number of engines (channels[part]) + if (inputs[IN_A_INPUT + part].getChannels() == 1) { + for (int c = 0; c < channels[part]; c += 4) + in[c / 4] = float_4(inputs[IN_A_INPUT + part].getVoltage()); + } + else { + for (int c = 0; c < channels[part]; c += 4) + in[c / 4] = inputs[IN_A_INPUT + part].getVoltageSimd(c); + } } else { std::memset(in, 0, sizeof(in)); } if (inputs[TRIGG_A_INPUT + part].isConnected()) { - add_input(inputs[TRIGG_A_INPUT + part], in_trig, channels_trig[part]); - // channelMask.apply_all(in_trig, channels_trig[part]); + // if TRIGG__INPUT is monophonic, broadcast to the active number of engines (channels[part]) + if (inputs[TRIGG_A_INPUT + part].getChannels() == 1) { + for (int c = 0; c < channels[part]; c += 4) + in_trig[c / 4] += float_4(inputs[TRIGG_A_INPUT + part].getVoltage()); + } + else { + for (int c = 0; c < channels[part]; c += 4) + in_trig[c / 4] += inputs[TRIGG_A_INPUT + part].getVoltageSimd(c); + } } if (inputs[EXP_CV_A_INPUT + part].isConnected()) { - load_input(inputs[EXP_CV_A_INPUT + part], expCV, channels[part]); + float_4 expCV[4]; + int expCVChannels = inputs[EXP_CV_A_INPUT + part].getChannels(); + // if EXP_CV__INPUT is monophonic, broadcast to the active number of engines (channels[part]) + if (expCVChannels == 1) { + for (int c = 0; c < channels[part]; c += 4) + expCV[c / 4] = float_4(inputs[EXP_CV_A_INPUT + part].getVoltage()); + } + else { + // otherwise read in the polyphonic expCV data, either to the number of active engines (channels[part]) + // or the number of channels of expCV, whichever is smaller + for (int c = 0; c < std::min(channels[part], expCVChannels); c += 4) + expCV[c / 4] = inputs[EXP_CV_A_INPUT + part].getVoltageSimd(c); + } + for (int c = 0; c < channels[part]; c += 4) { riseCV[c / 4] -= expCV[c / 4]; fallCV[c / 4] -= expCV[c / 4]; } } - add_input(inputs[RISE_CV_A_INPUT + part], riseCV, channels[part]); - add_input(inputs[FALL_CV_A_INPUT + part], fallCV, channels[part]); - add_input(inputs[CYCLE_A_INPUT + part], cycle, channels[part]); - // channelMask.apply(cycle, channels[part]); // check whether this is necessary + const int riseCVChannels = inputs[RISE_CV_A_INPUT + part].getChannels(); + // if EXP_CV__INPUT is monophonic, broadcast to the active number of engines (channels[part]) + if (riseCVChannels == 1) { + for (int c = 0; c < channels[part]; c += 4) + riseCV[c / 4] += float_4(inputs[RISE_CV_A_INPUT + part].getVoltage()); + } + else { + // otherwise read in the polyphonic rise CV data, either to the number of active engines (channels[part]) + // or the number of channels of expCV, whichever is smaller + for (int c = 0; c < std::min(channels[part], riseCVChannels); c += 4) + riseCV[c / 4] += inputs[RISE_CV_A_INPUT + part].getVoltageSimd(c); + } + + const int fallCVChannels = inputs[FALL_CV_A_INPUT + part].getChannels(); + if (fallCVChannels == 1) { + for (int c = 0; c < channels[part]; c += 4) + fallCV[c / 4] += float_4(inputs[FALL_CV_A_INPUT + part].getVoltage()); + } + else { + for (int c = 0; c < std::min(channels[part], fallCVChannels); c += 4) + fallCV[c / 4] += inputs[FALL_CV_A_INPUT + part].getVoltageSimd(c); + } - // start processing: + const int cycleChannels = inputs[CYCLE_A_INPUT + part].getChannels(); + if (cycleChannels == 1) { + for (int c = 0; c < channels[part]; c += 4) + cycle[c / 4] += float_4(inputs[CYCLE_A_INPUT + part].getVoltage()); + } + else { + for (int c = 0; c < std::min(channels[part], cycleChannels); c += 4) + cycle[c / 4] += inputs[CYCLE_A_INPUT + part].getVoltageSimd(c); + } + // start processing: for (int c = 0; c < channels[part]; c += 4) { // process SchmittTriggers - simd::float_4 trig_mask = trigger_4[part][c / 4].process(in_trig[c / 4] / 2.0); - gate[part][c / 4] = ifelse(trig_mask, simd::float_4::mask(), gate[part][c / 4]); - in[c / 4] = ifelse(gate[part][c / 4], simd::float_4(10.0f), in[c / 4]); + float_4 trig_mask = trigger_4[part][c / 4].process(in_trig[c / 4] / 2.0); + gate[part][c / 4] = ifelse(trig_mask, float_4::mask(), gate[part][c / 4]); + in[c / 4] = ifelse(gate[part][c / 4], float_4(10.0f), in[c / 4]); - simd::float_4 delta = in[c / 4] - out[part][c / 4]; + float_4 delta = in[c / 4] - out[part][c / 4]; // rise / fall branching - simd::float_4 delta_gt_0 = delta > simd::float_4::zero(); - simd::float_4 delta_lt_0 = delta < simd::float_4::zero(); - simd::float_4 delta_eq_0 = ~(delta_lt_0 | delta_gt_0); + float_4 delta_gt_0 = delta > float_4::zero(); + float_4 delta_lt_0 = delta < float_4::zero(); + float_4 delta_eq_0 = ~(delta_lt_0 | delta_gt_0); - simd::float_4 rateCV = ifelse(delta_gt_0, riseCV[c / 4], simd::float_4::zero()); + float_4 rateCV = ifelse(delta_gt_0, riseCV[c / 4], float_4::zero()); rateCV = ifelse(delta_lt_0, fallCV[c / 4], rateCV); - rateCV = clamp(rateCV, simd::float_4::zero(), simd::float_4(10.0f)); + rateCV = clamp(rateCV, float_4::zero(), float_4(10.0f)); - simd::float_4 rate = minTime * simd::pow(2.0f, rateCV); + float_4 rate = minTime * simd::pow(2.0f, rateCV); out[part][c / 4] += shapeDelta(delta, rate, shape) * args.sampleTime; - simd::float_4 rising = (in[c / 4] - out[part][c / 4]) > simd::float_4(1e-3); - simd::float_4 falling = (in[c / 4] - out[part][c / 4]) < simd::float_4(-1e-3); - simd::float_4 end_of_cycle = simd::andnot(falling, delta_lt_0); + float_4 rising = (in[c / 4] - out[part][c / 4]) > float_4(1e-3); + float_4 falling = (in[c / 4] - out[part][c / 4]) < float_4(-1e-3); + float_4 end_of_cycle = simd::andnot(falling, delta_lt_0); endOfCyclePulse[part][c / 4].trigger(end_of_cycle, 1e-3); - gate[part][c / 4] = ifelse(simd::andnot(rising, delta_gt_0), simd::float_4::zero(), gate[part][c / 4]); - gate[part][c / 4] = ifelse(end_of_cycle & (cycle[c / 4] >= simd::float_4(4.0f)), simd::float_4::mask(), gate[part][c / 4]); - gate[part][c / 4] = ifelse(delta_eq_0, simd::float_4::zero(), gate[part][c / 4]); + gate[part][c / 4] = ifelse(simd::andnot(rising, delta_gt_0), float_4::zero(), gate[part][c / 4]); + gate[part][c / 4] = ifelse(end_of_cycle & (cycle[c / 4] >= float_4(4.0f)), float_4::mask(), gate[part][c / 4]); + gate[part][c / 4] = ifelse(delta_eq_0, float_4::zero(), gate[part][c / 4]); out[part][c / 4] = ifelse(rising | falling, out[part][c / 4], in[c / 4]); - simd::float_4 out_rising = ifelse(rising, simd::float_4(10.0f), simd::float_4::zero()); - simd::float_4 out_falling = ifelse(falling, simd::float_4(10.0f), simd::float_4::zero()); + float_4 out_rising = ifelse(rising, float_4(10.0f), float_4::zero()); + float_4 out_falling = ifelse(falling, float_4(10.0f), float_4::zero()); - simd::float_4 pulse = endOfCyclePulse[part][c / 4].process(args.sampleTime); - simd::float_4 out_EOC = ifelse(pulse, simd::float_4(10.f), simd::float_4::zero()); + float_4 pulse = endOfCyclePulse[part][c / 4].process(args.sampleTime); + float_4 out_EOC = ifelse(pulse, float_4(10.f), float_4::zero()); out[part][c / 4].store(outputs[OUT_A_OUTPUT + part].getVoltages(c)); @@ -247,7 +299,6 @@ struct Rampage : Module { out_falling.store(outputs[FALLING_A_OUTPUT + part].getVoltages(c)); out_EOC.store(outputs[EOC_A_OUTPUT + part].getVoltages(c)); - } // for(int c, ...) if (channels[part] == 1) { @@ -281,17 +332,17 @@ struct Rampage : Module { for (int c = 0; c < channels_max; c += 4) { - simd::float_4 a = out[0][c / 4]; - simd::float_4 b = out[1][c / 4]; + float_4 a = out[0][c / 4]; + float_4 b = out[1][c / 4]; if (balance < 0.5) b *= 2.0f * balance; else if (balance > 0.5) a *= 2.0f * (1.0 - balance); - simd::float_4 comp = ifelse(b > a, simd::float_4(10.0f), simd::float_4::zero()); - simd::float_4 out_min = simd::fmin(a, b); - simd::float_4 out_max = simd::fmax(a, b); + float_4 comp = ifelse(b > a, float_4(10.0f), float_4::zero()); + float_4 out_min = simd::fmin(a, b); + float_4 out_max = simd::fmax(a, b); comp.store(outputs[COMPARATOR_OUTPUT].getVoltages(c)); out_min.store(outputs[MIN_OUTPUT].getVoltages(c)); @@ -325,10 +376,8 @@ struct Rampage : Module { }; - - struct RampageWidget : ModuleWidget { - RampageWidget(Rampage *module) { + RampageWidget(Rampage* module) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Rampage.svg"))); @@ -389,4 +438,4 @@ struct RampageWidget : ModuleWidget { }; -Model *modelRampage = createModel("Rampage"); +Model* modelRampage = createModel("Rampage"); diff --git a/src/SlewLimiter.cpp b/src/SlewLimiter.cpp index f87c735..c47677b 100644 --- a/src/SlewLimiter.cpp +++ b/src/SlewLimiter.cpp @@ -1,6 +1,7 @@ #include "plugin.hpp" #include "Common.hpp" -#include "simd_input.hpp" + +using simd::float_4; struct SlewLimiter : Module { enum ParamIds { @@ -20,7 +21,7 @@ struct SlewLimiter : Module { NUM_OUTPUTS }; - simd::float_4 out[4]; + float_4 out[4]; SlewLimiter() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); @@ -31,14 +32,14 @@ struct SlewLimiter : Module { memset(out, 0, sizeof(out)); } - void process(const ProcessArgs &args) override { - - simd::float_4 in[4]; - simd::float_4 riseCV[4]; - simd::float_4 fallCV[4]; + void process(const ProcessArgs& args) override { - int channels = inputs[IN_INPUT].getChannels(); + float_4 in[4] = {0.f}; + float_4 riseCV[4] = {0.f}; + float_4 fallCV[4] = {0.f}; + // this is the number of active polyphony engines, defined by the input + int numPolyphonyEngines = inputs[IN_INPUT].getChannels(); // minimum and std::maximum slopes in volts per second const float slewMin = 0.1; @@ -46,32 +47,45 @@ struct SlewLimiter : Module { // Amount of extra slew per voltage difference const float shapeScale = 1 / 10.f; - const simd::float_4 shape = simd::float_4(params[SHAPE_PARAM].getValue()); - const simd::float_4 param_rise = simd::float_4(params[RISE_PARAM].getValue() * 10.f); - const simd::float_4 param_fall = simd::float_4(params[FALL_PARAM].getValue() * 10.f); - - outputs[OUT_OUTPUT].setChannels(channels); + const float_4 shape = float_4(params[SHAPE_PARAM].getValue()); + const float_4 param_rise = float_4(params[RISE_PARAM].getValue() * 10.f); + const float_4 param_fall = float_4(params[FALL_PARAM].getValue() * 10.f); + + outputs[OUT_OUTPUT].setChannels(numPolyphonyEngines); + + for (int c = 0; c < numPolyphonyEngines; c += 4) { + in[c / 4] = inputs[IN_INPUT].getVoltageSimd(c); + + if (inputs[RISE_INPUT].isConnected()) { + if (inputs[RISE_INPUT].getChannels() == 1) { + riseCV[c / 4] = float_4(inputs[RISE_INPUT].getVoltage()); + } + else { + riseCV[c / 4] = inputs[RISE_INPUT].getVoltageSimd(c); + } + } + if (inputs[FALL_INPUT].isConnected()) { + if (inputs[FALL_INPUT].getChannels() == 1) { + fallCV[c / 4] = float_4(inputs[FALL_INPUT].getVoltage()); + } + else { + fallCV[c / 4] = inputs[FALL_INPUT].getVoltageSimd(c); + } + } - load_input(inputs[IN_INPUT], in, channels); - load_input(inputs[RISE_INPUT], riseCV, channels); - load_input(inputs[FALL_INPUT], fallCV, channels); - - for (int c = 0; c < channels; c += 4) { riseCV[c / 4] += param_rise; fallCV[c / 4] += param_fall; - simd::float_4 delta = in[c / 4] - out[c / 4]; - - simd::float_4 delta_gt_0 = delta > simd::float_4::zero(); - simd::float_4 delta_lt_0 = delta < simd::float_4::zero(); + float_4 delta = in[c / 4] - out[c / 4]; + float_4 delta_gt_0 = delta > float_4::zero(); + float_4 delta_lt_0 = delta < float_4::zero(); - simd::float_4 rateCV; - rateCV = ifelse(delta_gt_0, riseCV[c / 4], simd::float_4::zero()); + float_4 rateCV; + rateCV = ifelse(delta_gt_0, riseCV[c / 4], float_4::zero()); rateCV = ifelse(delta_lt_0, fallCV[c / 4], rateCV) * 0.1f; - simd::float_4 pm_one = simd::sgn(delta); - - simd::float_4 slew = slewMax * simd::pow(simd::float_4(slewMin / slewMax), rateCV); + float_4 pm_one = simd::sgn(delta); + float_4 slew = slewMax * simd::pow(float_4(slewMin / slewMax), rateCV); out[c / 4] += slew * simd::crossfade(pm_one, shapeScale * delta, shape) * args.sampleTime; out[c / 4] = ifelse(delta_gt_0 & (out[c / 4] > in[c / 4]), in[c / 4], out[c / 4]); @@ -84,7 +98,7 @@ struct SlewLimiter : Module { struct SlewLimiterWidget : ModuleWidget { - SlewLimiterWidget(::SlewLimiter *module) { + SlewLimiterWidget(SlewLimiter* module) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/SlewLimiter.svg"))); @@ -105,4 +119,4 @@ struct SlewLimiterWidget : ModuleWidget { }; -Model *modelSlewLimiter = createModel<::SlewLimiter, SlewLimiterWidget>("SlewLimiter"); +Model* modelSlewLimiter = createModel<::SlewLimiter, SlewLimiterWidget>("SlewLimiter"); diff --git a/src/simd_input.hpp b/src/simd_input.hpp deleted file mode 100644 index 4b1265f..0000000 --- a/src/simd_input.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "rack.hpp" - - -inline void load_input(Input &in, simd::float_4 *v, int numChannels) { - int inChannels = in.getChannels(); - if (inChannels == 1) { - for (int i = 0; i < numChannels; i++) - v[i] = simd::float_4(in.getVoltage()); - } - else { - for (int c = 0; c < inChannels; c += 4) - v[c / 4] = simd::float_4::load(in.getVoltages(c)); - } -} - -inline void add_input(Input &in, simd::float_4 *v, int numChannels) { - int inChannels = in.getChannels(); - if (inChannels == 1) { - for (int i = 0; i < numChannels; i++) - v[i] += simd::float_4(in.getVoltage()); - } - else { - for (int c = 0; c < inChannels; c += 4) - v[c / 4] += simd::float_4::load(in.getVoltages(c)); - } -}