diff --git a/plugin.json b/plugin.json index bad3264..90b15b2 100644 --- a/plugin.json +++ b/plugin.json @@ -33,7 +33,8 @@ "tags": [ "Ring Modulator", "Attenuator", - "Dual" + "Dual", + "Polyphonic" ] }, { @@ -47,7 +48,8 @@ "slug": "Mixer", "name": "Mixer", "tags": [ - "Mixer" + "Mixer", + "Polyphonic" ] }, { @@ -55,7 +57,8 @@ "name": "Slew Limiter", "tags": [ "Slew Limiter", - "Envelope Follower" + "Envelope Follower", + "Polyphonic" ] }, { @@ -63,7 +66,8 @@ "name": "Dual Atenuverter", "tags": [ "Attenuator", - "Dual" + "Dual", + "Polyphonic" ] } ] diff --git a/src/ABC.cpp b/src/ABC.cpp index 4de5a22..774f8d3 100644 --- a/src/ABC.cpp +++ b/src/ABC.cpp @@ -1,5 +1,6 @@ #include "plugin.hpp" +#define MAX(a,b) (a>b)?a:b static float clip(float x) { @@ -10,6 +11,26 @@ static float clip(float x) { / (1. + 1.54167*std::pow(x, 12) + 0.642361*std::pow(x, 24) + 0.0579909*std::pow(x, 36)); } +static simd::float_4 clip4(simd::float_4 x) { + // Pade approximant of x/(1 + x^12)^(1/12) + const simd::float_4 limit = simd::float_4(1.16691853009184); + const simd::float_4 cnst_10 = simd::float_4(10.0); + const simd::float_4 cnst_1 = simd::float_4(1.0); + const simd::float_4 cnst_01 = simd::float_4(0.1); + + const simd::float_4 coeff_1 = simd::float_4(1.45833); + const simd::float_4 coeff_2 = simd::float_4(0.559028); + const simd::float_4 coeff_3 = simd::float_4(0.0427035); + const simd::float_4 coeff_4 = simd::float_4(1.54167); + const simd::float_4 coeff_5 = simd::float_4(0.642361); + const simd::float_4 coeff_6 = simd::float_4(0.0579909); + + x = clamp(x*cnst_01, -limit, limit); + return cnst_10 * (x + coeff_1*simd::pow(x, 13) + coeff_2*simd::pow(x, 25) + coeff_3*simd::pow(x, 37)) + / (cnst_1 + coeff_4*simd::pow(x, 12) + coeff_5*simd::pow(x, 24) + coeff_6*simd::pow(x, 36)); +} + + static float exponentialBipolar80Pade_5_4(float x) { return (0.109568*x + 0.281588*std::pow(x, 3) + 0.133841*std::pow(x, 5)) / (1. - 0.630374*std::pow(x, 2) + 0.166271*std::pow(x, 4)); @@ -44,41 +65,156 @@ struct ABC : Module { NUM_LIGHTS }; + simd::float_4 mask[4]; + + ABC() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(B1_LEVEL_PARAM, -1.0, 1.0, 0.0, "B1 Level"); configParam(C1_LEVEL_PARAM, -1.0, 1.0, 0.0, "C1 Level"); configParam(B2_LEVEL_PARAM, -1.0, 1.0, 0.0, "B2 Level"); configParam(C2_LEVEL_PARAM, -1.0, 1.0, 0.0, "C2 Level"); + + __m128i tmp = _mm_cmpeq_epi16(_mm_set_epi32(0,0,0,0),_mm_set_epi32(0,0,0,0)); + + for(int i=0; i<4; i++) { + mask[3-i] = simd::float_4(_mm_castsi128_ps(tmp)); + tmp = _mm_srli_si128(tmp, 4); + } + + } + + inline void load_input(Input &in, simd::float_4 *v, int numChannels) { + if(numChannels==1) { + for(int i=0; i<4; i++) v[i] = simd::float_4(in.getVoltage()); + } else { + for(int c=0; c0?channels1:1; + int channels2 = inputs[IN2_INPUT].getChannels(); channels2 = channels2>0?channels2:1; + + simd::float_4 att1 = simd::float_4(params[ATEN1_PARAM].getValue()); + simd::float_4 att2 = simd::float_4(params[ATEN2_PARAM].getValue()); + + simd::float_4 offset1 = simd::float_4(params[OFFSET1_PARAM].getValue()); + simd::float_4 offset2 = simd::float_4(params[OFFSET2_PARAM].getValue()); + + + for (int c = 0; c < channels1; c += 4) out1[c / 4] = clamp(simd::float_4::load(inputs[IN1_INPUT].getVoltages(c)) * att1 + offset1, -10.f, 10.f); + for (int c = 0; c < channels2; c += 4) out2[c / 4] = clamp(simd::float_4::load(inputs[IN2_INPUT].getVoltages(c)) * att2 + offset2, -10.f, 10.f); + + outputs[OUT1_OUTPUT].setChannels(channels1); + outputs[OUT2_OUTPUT].setChannels(channels2); + + for (int c = 0; c < channels1; c += 4) out1[c / 4].store(outputs[OUT1_OUTPUT].getVoltages(c)); + for (int c = 0; c < channels2; c += 4) out2[c / 4].store(outputs[OUT2_OUTPUT].getVoltages(c)); + + float light1 = outputs[OUT1_OUTPUT].getVoltageSum()/channels1; + float light2 = outputs[OUT2_OUTPUT].getVoltageSum()/channels2; + + lights[OUT1_POS_LIGHT].setSmoothBrightness(light1 / 5.f, args.sampleTime); + lights[OUT1_NEG_LIGHT].setSmoothBrightness(-light1 / 5.f, args.sampleTime); + lights[OUT2_POS_LIGHT].setSmoothBrightness(light2 / 5.f, args.sampleTime); + lights[OUT2_NEG_LIGHT].setSmoothBrightness(-light2 / 5.f, args.sampleTime); } }; diff --git a/src/EvenVCO.cpp b/src/EvenVCO.cpp index db7b0bc..088c6a4 100644 --- a/src/EvenVCO.cpp +++ b/src/EvenVCO.cpp @@ -1,5 +1,6 @@ #include "plugin.hpp" +#define MAX(a,b) (a>b)?a:b struct EvenVCO : Module { enum ParamIds { @@ -47,11 +48,25 @@ struct EvenVCO : Module { configParam(OCTAVE_PARAM, -5.0, 4.0, 0.0, "Octave", "'", 0.5); configParam(TUNE_PARAM, -7.0, 7.0, 0.0, "Tune", " semitones"); configParam(PWM_PARAM, -1.0, 1.0, 0.0, "Pulse width"); + + } void process(const ProcessArgs &args) override { // Compute frequency, pitch is 1V/oct - float pitch = 1.f + std::round(params[OCTAVE_PARAM].getValue()) + params[TUNE_PARAM].getValue() / 12.f; + + int channels_pitch1 = inputs[PITCH1_INPUT].getChannels(); + int channels_pitch2 = inputs[PITCH2_INPUT].getChannels(); + int channels_fm = inputs[FM_INPUT].getChannels(); + + int channels = 1; + channels = MAX(channels, channels_pitch1); + channels = MAX(channels, channels_pitch2); + // channels = MAX(channels, channels_fm); + + float pitch_0 = 1.f + std::round(params[OCTAVE_PARAM].getValue()) + params[TUNE_PARAM].getValue() / 12.f; + + pitch += inputs[PITCH1_INPUT].getVoltage() + inputs[PITCH2_INPUT].getVoltage(); pitch += inputs[FM_INPUT].getVoltage() / 4.f; float freq = dsp::FREQ_C4 * std::pow(2.f, pitch); diff --git a/src/Mixer.cpp b/src/Mixer.cpp index d097e75..4e77bb6 100644 --- a/src/Mixer.cpp +++ b/src/Mixer.cpp @@ -1,5 +1,8 @@ #include "plugin.hpp" +#define MAX(a,b) (a>b)?a:b +#define MIN(a,b) (a out) { - float rise = inputs[RISE_INPUT].getVoltage() / 10.f + params[RISE_PARAM].getValue(); - float slew = slewMax * std::pow(slewMin / slewMax, rise); - out += slew * crossfade(1.f, shapeScale * (in - out), shape) * args.sampleTime; - if (out > in) - out = in; - } - // Fall - else if (in < out) { - float fall = inputs[FALL_INPUT].getVoltage() / 10.f + params[FALL_PARAM].getValue(); - float slew = slewMax * std::pow(slewMin / slewMax, fall); - out -= slew * crossfade(1.f, shapeScale * (out - in), shape) * args.sampleTime; - if (out < in) - out = in; + const float param_rise = params[RISE_PARAM].getValue(); + const float param_fall = params[FALL_PARAM].getValue(); + + + outputs[OUT_OUTPUT].setChannels(channels); + + for(int c=0; c out[c]) { + float rise = inputs[RISE_INPUT].getPolyVoltage(c) / 10.f + param_rise; + float slew = slewMax * std::pow(slewMin / slewMax, rise); + out[c] += slew * crossfade(1.f, shapeScale * (in - out[c]), shape) * args.sampleTime; + if (out[c] > in) + out[c] = in; + } + // Fall + else if (in < out[c]) { + float fall = inputs[FALL_INPUT].getPolyVoltage(c) / 10.f + param_fall; + float slew = slewMax * std::pow(slewMin / slewMax, fall); + out[c] -= slew * crossfade(1.f, shapeScale * (out[c] - in), shape) * args.sampleTime; + if (out[c] < in) + out[c] = in; + } + } + outputs[OUT_OUTPUT].writeVoltages(out); - outputs[OUT_OUTPUT].setVoltage(out); } }; diff --git a/src/SpringReverb.cpp b/src/SpringReverb.cpp index 27ebe1d..be9c4c0 100644 --- a/src/SpringReverb.cpp +++ b/src/SpringReverb.cpp @@ -65,8 +65,8 @@ struct SpringReverb : Module { } void process(const ProcessArgs &args) override { - float in1 = inputs[IN1_INPUT].getVoltage(); - float in2 = inputs[IN2_INPUT].getVoltage(); + float in1 = inputs[IN1_INPUT].getVoltageSum(); + float in2 = inputs[IN2_INPUT].getVoltageSum(); const float levelScale = 0.030; const float levelBase = 25.0; float level1 = levelScale * dsp::exponentialBipolar(levelBase, params[LEVEL1_PARAM].getValue()) * inputs[CV1_INPUT].getNormalVoltage(10.0) / 10.0;