Signed-off-by: hemmer <915048+hemmer@users.noreply.github.com>tags/v1.1.0^2
| @@ -1,4 +1,5 @@ | |||||
| #include "plugin.hpp" | #include "plugin.hpp" | ||||
| #include "simd_mask.hpp" | |||||
| #define MAX(a,b) (a>b)?a:b | #define MAX(a,b) (a>b)?a:b | ||||
| @@ -65,7 +66,9 @@ struct ABC : Module { | |||||
| NUM_LIGHTS | NUM_LIGHTS | ||||
| }; | }; | ||||
| simd::float_4 mask[4]; | |||||
| // simd::float_4 mask[4]; | |||||
| ChannelMask channelMask; | |||||
| ABC() { | ABC() { | ||||
| @@ -75,27 +78,19 @@ struct ABC : Module { | |||||
| configParam(B2_LEVEL_PARAM, -1.0, 1.0, 0.0, "B2 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"); | 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)); | __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++) { | for(int i=0; i<4; i++) { | ||||
| mask[3-i] = simd::float_4(_mm_castsi128_ps(tmp)); | mask[3-i] = simd::float_4(_mm_castsi128_ps(tmp)); | ||||
| tmp = _mm_srli_si128(tmp, 4); | 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; c<numChannels; c+=4) v[c/4] = simd::float_4::load(in.getVoltages(c)); | |||||
| } | |||||
| } | |||||
| inline void crop_channels(simd::float_4 *vec, int numChannels) { | |||||
| int c=numChannels/4; | |||||
| vec[c] = simd::float_4(_mm_and_ps(vec[c].v, mask[numChannels-4*c].v)); | |||||
| } | |||||
| void process(const ProcessArgs &args) override { | void process(const ProcessArgs &args) override { | ||||
| @@ -123,7 +118,7 @@ struct ABC : Module { | |||||
| channels_1 = MAX(channels_1, channels_B1); | channels_1 = MAX(channels_1, channels_B1); | ||||
| channels_1 = MAX(channels_1, channels_C1); | channels_1 = MAX(channels_1, channels_C1); | ||||
| int channels_2 = channels_1; | |||||
| int channels_2 = 1; | |||||
| channels_2 = MAX(channels_2, channels_A2); | channels_2 = MAX(channels_2, channels_A2); | ||||
| channels_2 = MAX(channels_2, channels_B2); | channels_2 = MAX(channels_2, channels_B2); | ||||
| channels_2 = MAX(channels_2, channels_C2); | channels_2 = MAX(channels_2, channels_C2); | ||||
| @@ -136,7 +131,7 @@ struct ABC : Module { | |||||
| load_input(inputs[A1_INPUT], a1, channels_A1); | load_input(inputs[A1_INPUT], a1, channels_A1); | ||||
| crop_channels(a1, channels_1); | |||||
| channelMask.apply(a1, channels_1); | |||||
| if(inputs[B1_INPUT].isConnected()) { | if(inputs[B1_INPUT].isConnected()) { | ||||
| load_input(inputs[B1_INPUT], b1, channels_B1); | load_input(inputs[B1_INPUT], b1, channels_B1); | ||||
| @@ -144,7 +139,7 @@ struct ABC : Module { | |||||
| } else { | } 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<channels_1; c+=4) b1[c/4] = simd::float_4(5.f*mult_B1); | ||||
| } | } | ||||
| crop_channels(b1, channels_1); | |||||
| channelMask.apply(b1, channels_1); | |||||
| if(inputs[C1_INPUT].isConnected()) { | if(inputs[C1_INPUT].isConnected()) { | ||||
| load_input(inputs[C1_INPUT], c1, channels_C1); | load_input(inputs[C1_INPUT], c1, channels_C1); | ||||
| @@ -152,14 +147,14 @@ struct ABC : Module { | |||||
| } else { | } 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<channels_1; c+=4) c1[c/4] = simd::float_4(10.f*mult_C1); | ||||
| } | } | ||||
| crop_channels(c1, channels_1); | |||||
| channelMask.apply(c1, channels_1); | |||||
| 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<channels_1; c+=4) out1[c/4] = clip4(a1[c/4] * b1[c/4] + c1[c/4]); | ||||
| load_input(inputs[A1_INPUT], a1, channels_A1); | |||||
| crop_channels(a1, channels_1); | |||||
| load_input(inputs[A2_INPUT], a2, channels_A2); | |||||
| channelMask.apply(a2, channels_2); | |||||
| if(inputs[B2_INPUT].isConnected()) { | if(inputs[B2_INPUT].isConnected()) { | ||||
| load_input(inputs[B2_INPUT], b2, channels_B2); | load_input(inputs[B2_INPUT], b2, channels_B2); | ||||
| @@ -167,7 +162,7 @@ struct ABC : Module { | |||||
| } else { | } 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<channels_2; c+=4) b2[c/4] = simd::float_4(5.f*mult_B2); | ||||
| } | } | ||||
| crop_channels(b2, channels_2); | |||||
| channelMask.apply(b2, channels_2); | |||||
| if(inputs[C2_INPUT].isConnected()) { | if(inputs[C2_INPUT].isConnected()) { | ||||
| load_input(inputs[C2_INPUT], c2, channels_C2); | load_input(inputs[C2_INPUT], c2, channels_C2); | ||||
| @@ -175,7 +170,7 @@ struct ABC : Module { | |||||
| } else { | } 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<channels_2; c+=4) c2[c/4] = simd::float_4(10.f*mult_C2); | ||||
| } | } | ||||
| crop_channels(c2, channels_2); | |||||
| channelMask.apply(c2, channels_2); | |||||
| for(int c=0; c<channels_2; c+=4) out2[c/4] = clip4(a2[c/4] * b2[c/4] + c2[c/4]); | for(int c=0; c<channels_2; c+=4) out2[c/4] = clip4(a2[c/4] * b2[c/4] + c2[c/4]); | ||||
| @@ -188,10 +183,12 @@ struct ABC : Module { | |||||
| } | } | ||||
| else { | else { | ||||
| for(int c=0; c<channels_1; c+=4) out2[c/4] += out1[c/4]; | for(int c=0; c<channels_1; c+=4) out2[c/4] += out1[c/4]; | ||||
| channels_2 = MAX(channels_1, channels_2); | |||||
| } | } | ||||
| if (outputs[OUT2_OUTPUT].isConnected()) { | if (outputs[OUT2_OUTPUT].isConnected()) { | ||||
| outputs[OUT2_OUTPUT].setChannels(channels_1); | |||||
| for(int c=0; c<channels_1; c+=4) out2[c/4].store(outputs[OUT2_OUTPUT].getVoltages(c)); | |||||
| outputs[OUT2_OUTPUT].setChannels(channels_2); | |||||
| for(int c=0; c<channels_2; c+=4) out2[c/4].store(outputs[OUT2_OUTPUT].getVoltages(c)); | |||||
| } | } | ||||
| // Lights | // Lights | ||||
| @@ -1,4 +1,5 @@ | |||||
| #include "plugin.hpp" | #include "plugin.hpp" | ||||
| #include "simd_mask.hpp" | |||||
| struct DualAtenuverter : Module { | struct DualAtenuverter : Module { | ||||
| @@ -49,7 +50,6 @@ struct DualAtenuverter : Module { | |||||
| simd::float_4 offset1 = simd::float_4(params[OFFSET1_PARAM].getValue()); | simd::float_4 offset1 = simd::float_4(params[OFFSET1_PARAM].getValue()); | ||||
| simd::float_4 offset2 = simd::float_4(params[OFFSET2_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 < 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); | 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); | ||||
| @@ -1,4 +1,5 @@ | |||||
| #include "plugin.hpp" | #include "plugin.hpp" | ||||
| #include "simd_mask.hpp" | |||||
| #define MAX(a,b) (a>b)?a:b | #define MAX(a,b) (a>b)?a:b | ||||
| @@ -26,38 +27,73 @@ struct EvenVCO : Module { | |||||
| NUM_OUTPUTS | NUM_OUTPUTS | ||||
| }; | }; | ||||
| float phase = 0.0; | |||||
| simd::float_4 phase[4]; | |||||
| simd::float_4 tri[4]; | |||||
| /** The value of the last sync input */ | /** The value of the last sync input */ | ||||
| float sync = 0.0; | float sync = 0.0; | ||||
| /** The outputs */ | /** The outputs */ | ||||
| float tri = 0.0; | |||||
| /** Whether we are past the pulse width already */ | /** Whether we are past the pulse width already */ | ||||
| bool halfPhase = false; | |||||
| bool halfPhase[PORT_MAX_CHANNELS]; | |||||
| dsp::MinBlepGenerator<16, 32> triSquareMinBlep; | |||||
| dsp::MinBlepGenerator<16, 32> triMinBlep; | |||||
| dsp::MinBlepGenerator<16, 32> sineMinBlep; | |||||
| dsp::MinBlepGenerator<16, 32> doubleSawMinBlep; | |||||
| dsp::MinBlepGenerator<16, 32> sawMinBlep; | |||||
| dsp::MinBlepGenerator<16, 32> squareMinBlep; | |||||
| dsp::MinBlepGenerator<16, 32> triSquareMinBlep[PORT_MAX_CHANNELS]; | |||||
| dsp::MinBlepGenerator<16, 32> triMinBlep[PORT_MAX_CHANNELS]; | |||||
| dsp::MinBlepGenerator<16, 32> sineMinBlep[PORT_MAX_CHANNELS]; | |||||
| dsp::MinBlepGenerator<16, 32> doubleSawMinBlep[PORT_MAX_CHANNELS]; | |||||
| dsp::MinBlepGenerator<16, 32> sawMinBlep[PORT_MAX_CHANNELS]; | |||||
| dsp::MinBlepGenerator<16, 32> squareMinBlep[PORT_MAX_CHANNELS]; | |||||
| dsp::RCFilter triFilter; | dsp::RCFilter triFilter; | ||||
| ChannelMask channelMask; | |||||
| EvenVCO() { | EvenVCO() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | ||||
| configParam(OCTAVE_PARAM, -5.0, 4.0, 0.0, "Octave", "'", 0.5); | configParam(OCTAVE_PARAM, -5.0, 4.0, 0.0, "Octave", "'", 0.5); | ||||
| configParam(TUNE_PARAM, -7.0, 7.0, 0.0, "Tune", " semitones"); | configParam(TUNE_PARAM, -7.0, 7.0, 0.0, "Tune", " semitones"); | ||||
| configParam(PWM_PARAM, -1.0, 1.0, 0.0, "Pulse width"); | 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); | |||||
| } | |||||
| for(int c=0; c<PORT_MAX_CHANNELS; c++) halfPhase[c] = false; | |||||
| } | |||||
| /* | |||||
| 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; c<numChannels; c+=4) v[c/4] = simd::float_4::load(in.getVoltages(c)); | |||||
| } | |||||
| } | |||||
| */ | |||||
| inline void add_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; c<numChannels; c+=4) v[c/4] = simd::float_4::load(in.getVoltages(c)); | |||||
| } | |||||
| } | } | ||||
| void process(const ProcessArgs &args) override { | void process(const ProcessArgs &args) override { | ||||
| // Compute frequency, pitch is 1V/oct | |||||
| 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]; | |||||
| int channels_pitch1 = inputs[PITCH1_INPUT].getChannels(); | int channels_pitch1 = inputs[PITCH1_INPUT].getChannels(); | ||||
| int channels_pitch2 = inputs[PITCH2_INPUT].getChannels(); | int channels_pitch2 = inputs[PITCH2_INPUT].getChannels(); | ||||
| int channels_fm = inputs[FM_INPUT].getChannels(); | int channels_fm = inputs[FM_INPUT].getChannels(); | ||||
| int channels_pwm = inputs[PWM_INPUT].getChannels(); | |||||
| int channels = 1; | int channels = 1; | ||||
| channels = MAX(channels, channels_pitch1); | channels = MAX(channels, channels_pitch1); | ||||
| @@ -66,68 +102,151 @@ struct EvenVCO : Module { | |||||
| float pitch_0 = 1.f + std::round(params[OCTAVE_PARAM].getValue()) + params[TUNE_PARAM].getValue() / 12.f; | float pitch_0 = 1.f + std::round(params[OCTAVE_PARAM].getValue()) + params[TUNE_PARAM].getValue() / 12.f; | ||||
| // Compute frequency, pitch is 1V/oct | |||||
| for(int c=0; c<channels; c+=4) pitch[c/4] = simd::float_4(pitch_0); | |||||
| if(inputs[PITCH1_INPUT].isConnected()) { | |||||
| load_input(inputs[PITCH1_INPUT], pitch_1, channels_pitch1); | |||||
| channelMask.apply(pitch_1, channels_pitch1); | |||||
| for(int c=0; c<channels_pitch1; c+=4) pitch[c/4] += pitch_1[c/4]; | |||||
| } | |||||
| if(inputs[PITCH2_INPUT].isConnected()) { | |||||
| load_input(inputs[PITCH2_INPUT], pitch_2, channels_pitch2); | |||||
| channelMask.apply(pitch_2, channels_pitch2); | |||||
| for(int c=0; c<channels_pitch2; c+=4) pitch[c/4] += pitch_2[c/4]; | |||||
| } | |||||
| if(inputs[FM_INPUT].isConnected()) { | |||||
| load_input(inputs[FM_INPUT], pitch_fm, channels_fm); | |||||
| channelMask.apply(pitch_fm, channels_fm); | |||||
| for(int c=0; c<channels_fm; c+=4) pitch[c/4] += pitch_fm[c/4] / 4.f; | |||||
| } | |||||
| 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); | |||||
| } | |||||
| 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); | |||||
| freq = clamp(freq, 0.f, 20000.f); | |||||
| // Pulse width | // Pulse width | ||||
| float pw = params[PWM_PARAM].getValue() + inputs[PWM_INPUT].getVoltage() / 5.f; | |||||
| const float minPw = 0.05; | |||||
| pw = rescale(clamp(pw, -1.f, 1.f), -1.f, 1.f, minPw, 1.f - minPw); | |||||
| // Advance phase | |||||
| float deltaPhase = clamp(freq * args.sampleTime, 1e-6f, 0.5f); | |||||
| float oldPhase = phase; | |||||
| phase += deltaPhase; | |||||
| if (oldPhase < 0.5 && phase >= 0.5) { | |||||
| float crossing = -(phase - 0.5) / deltaPhase; | |||||
| triSquareMinBlep.insertDiscontinuity(crossing, 2.f); | |||||
| doubleSawMinBlep.insertDiscontinuity(crossing, -2.f); | |||||
| float pw_0 = params[PWM_PARAM].getValue(); | |||||
| for(int c=0; c<channels; c+=4) pw[c/4] = simd::float_4(pw_0); | |||||
| if(inputs[PWM_INPUT].isConnected()) { | |||||
| load_input(inputs[PWM_INPUT], pwm, channels_pwm); | |||||
| channelMask.apply(pwm, channels_pwm); | |||||
| for(int c=0; c<channels_pwm; c+=4) pw[c/4] += pwm[c/4] / 5.f; | |||||
| } | } | ||||
| if (!halfPhase && phase >= pw) { | |||||
| float crossing = -(phase - pw) / deltaPhase; | |||||
| squareMinBlep.insertDiscontinuity(crossing, 2.f); | |||||
| halfPhase = true; | |||||
| 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); | |||||
| 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)); | |||||
| oldPhase[c/4] = phase[c/4]; | |||||
| phase[c/4] += deltaPhase[c/4]; | |||||
| } | |||||
| // the next block can't be done with SIMD instructions: | |||||
| for(int c=0; c<channels; c++) { | |||||
| if (oldPhase[c/4].s[c%4] < 0.5 && phase[c/4].s[c%4] >= 0.5) { | |||||
| float crossing = -(phase[c/4].s[c%4] - 0.5) / deltaPhase[c/4].s[c%4]; | |||||
| triSquareMinBlep[c].insertDiscontinuity(crossing, 2.f); | |||||
| doubleSawMinBlep[c].insertDiscontinuity(crossing, -2.f); | |||||
| } | |||||
| if (!halfPhase[c] && phase[c/4].s[c%4] >= pw[c/4].s[c%4]) { | |||||
| float crossing = -(phase[c/4].s[c%4] - pw[c/4].s[c%4]) / deltaPhase[c/4].s[c%4]; | |||||
| squareMinBlep[c].insertDiscontinuity(crossing, 2.f); | |||||
| halfPhase[c] = true; | |||||
| } | |||||
| // Reset phase if at end of cycle | |||||
| if (phase[c/4].s[c%4] >= 1.f) { | |||||
| phase[c/4].s[c%4] -= 1.f; | |||||
| float crossing = -phase[c/4].s[c%4] / deltaPhase[c/4].s[c%4]; | |||||
| triSquareMinBlep[c].insertDiscontinuity(crossing, -2.f); | |||||
| doubleSawMinBlep[c].insertDiscontinuity(crossing, -2.f); | |||||
| squareMinBlep[c].insertDiscontinuity(crossing, -2.f); | |||||
| sawMinBlep[c].insertDiscontinuity(crossing, -2.f); | |||||
| halfPhase[c] = false; | |||||
| } | |||||
| } | } | ||||
| // Reset phase if at end of cycle | |||||
| if (phase >= 1.f) { | |||||
| phase -= 1.f; | |||||
| float crossing = -phase / deltaPhase; | |||||
| triSquareMinBlep.insertDiscontinuity(crossing, -2.f); | |||||
| doubleSawMinBlep.insertDiscontinuity(crossing, -2.f); | |||||
| squareMinBlep.insertDiscontinuity(crossing, -2.f); | |||||
| sawMinBlep.insertDiscontinuity(crossing, -2.f); | |||||
| halfPhase = false; | |||||
| simd::float_4 triSquareMinBlepOut[4]; | |||||
| simd::float_4 doubleSawMinBlepOut[4]; | |||||
| simd::float_4 sawMinBlepOut[4]; | |||||
| simd::float_4 squareMinBlepOut[4]; | |||||
| simd::float_4 triSquare[4]; | |||||
| simd::float_4 sine[4]; | |||||
| simd::float_4 doubleSaw[4]; | |||||
| simd::float_4 even[4]; | |||||
| simd::float_4 saw[4]; | |||||
| simd::float_4 square[4]; | |||||
| simd::float_4 triOut[4]; | |||||
| for(int c=0; c<channels; c++) { | |||||
| triSquareMinBlepOut[c/4].s[c%4] = triSquareMinBlep[c].process(); | |||||
| doubleSawMinBlepOut[c/4].s[c%4] = doubleSawMinBlep[c].process(); | |||||
| sawMinBlepOut[c/4].s[c%4] = sawMinBlep[c].process(); | |||||
| squareMinBlepOut[c/4].s[c%4] = squareMinBlep[c].process(); | |||||
| } | } | ||||
| // Outputs | // Outputs | ||||
| float triSquare = (phase < 0.5) ? -1.f : 1.f; | |||||
| triSquare += triSquareMinBlep.process(); | |||||
| // Integrate square for triangle | |||||
| tri += 4.f * triSquare * freq * args.sampleTime; | |||||
| tri *= (1.f - 40.f * args.sampleTime); | |||||
| float sine = -std::cos(2*M_PI * phase); | |||||
| float doubleSaw = (phase < 0.5) ? (-1.f + 4.f*phase) : (-1.f + 4.f*(phase - 0.5)); | |||||
| doubleSaw += doubleSawMinBlep.process(); | |||||
| float even = 0.55 * (doubleSaw + 1.27 * sine); | |||||
| float saw = -1.f + 2.f*phase; | |||||
| saw += sawMinBlep.process(); | |||||
| float square = (phase < pw) ? -1.f : 1.f; | |||||
| square += squareMinBlep.process(); | |||||
| // Set outputs | |||||
| outputs[TRI_OUTPUT].setVoltage(5.f*tri); | |||||
| outputs[SINE_OUTPUT].setVoltage(5.f*sine); | |||||
| outputs[EVEN_OUTPUT].setVoltage(5.f*even); | |||||
| outputs[SAW_OUTPUT].setVoltage(5.f*saw); | |||||
| outputs[SQUARE_OUTPUT].setVoltage(5.f*square); | |||||
| outputs[TRI_OUTPUT].setChannels(channels); | |||||
| outputs[SINE_OUTPUT].setChannels(channels); | |||||
| outputs[EVEN_OUTPUT].setChannels(channels); | |||||
| outputs[SAW_OUTPUT].setChannels(channels); | |||||
| outputs[SQUARE_OUTPUT].setChannels(channels); | |||||
| for(int c=0; c<channels; c+=4) { | |||||
| triSquare[c/4] = simd::ifelse( (phase[c/4] < 0.5f*one_4), m_one_4, one_4); | |||||
| triSquare[c/4] += triSquareMinBlepOut[c/4]; | |||||
| // Integrate square for triangle | |||||
| tri[c/4] += (4.f * triSquare[c/4]) * (freq[c/4] * args.sampleTime); | |||||
| tri[c/4] *= (1.f - 40.f * args.sampleTime); | |||||
| triOut[c/4] = 5.f * tri[c/4]; | |||||
| sine[c/4] = 5.f * simd::cos(2*M_PI * phase[c/4]); | |||||
| doubleSaw[c/4] = simd::ifelse( (phase[c/4] < 0.5), (-1.f + 4.f*phase[c/4]), (-1.f + 4.f*(phase[c/4] - 0.5f))); | |||||
| doubleSaw[c/4] += doubleSawMinBlepOut[c/4]; | |||||
| doubleSaw[c/4] *= 5.f; | |||||
| even[c/4] = 0.55 * (doubleSaw[c/4] + 1.27 * sine[c/4]); | |||||
| saw[c/4] = -1.f + 2.f*phase[c/4]; | |||||
| saw[c/4] += sawMinBlepOut[c/4]; | |||||
| saw[c/4] *= 5.f; | |||||
| square[c/4] = simd::ifelse( (phase[c/4] < pw[c/4]), m_one_4, one_4) ; | |||||
| square[c/4] += squareMinBlepOut[c/4]; | |||||
| square[c/4] *= 5.f; | |||||
| // Set outputs | |||||
| triOut[c/4].store(outputs[TRI_OUTPUT].getVoltages(c)); | |||||
| sine[c/4].store(outputs[SINE_OUTPUT].getVoltages(c)); | |||||
| even[c/4].store(outputs[EVEN_OUTPUT].getVoltages(c)); | |||||
| saw[c/4].store(outputs[SAW_OUTPUT].getVoltages(c)); | |||||
| square[c/4].store(outputs[SQUARE_OUTPUT].getVoltages(c)); | |||||
| } | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -1,4 +1,6 @@ | |||||
| #include "plugin.hpp" | #include "plugin.hpp" | ||||
| #include "simd_mask.hpp" | |||||
| #define MAX(a,b) (a>b)?a:b | #define MAX(a,b) (a>b)?a:b | ||||
| #define MIN(a,b) (a<b)?a:b | #define MIN(a,b) (a<b)?a:b | ||||
| @@ -30,9 +32,10 @@ struct Mixer : Module { | |||||
| NUM_LIGHTS | NUM_LIGHTS | ||||
| }; | }; | ||||
| simd::float_4 mask[4]; | |||||
| simd::float_4 minus_one; | simd::float_4 minus_one; | ||||
| ChannelMask channelMask; | |||||
| Mixer() { | Mixer() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
| configParam(CH1_PARAM, 0.0, 1.0, 0.0, "Ch 1 level", "%", 0, 100); | configParam(CH1_PARAM, 0.0, 1.0, 0.0, "Ch 1 level", "%", 0, 100); | ||||
| @@ -42,12 +45,6 @@ struct Mixer : Module { | |||||
| minus_one = simd::float_4(-1.0f); | minus_one = simd::float_4(-1.0f); | ||||
| __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); | |||||
| } | |||||
| } | } | ||||
| @@ -90,28 +87,28 @@ struct Mixer : Module { | |||||
| for(int c=0; c<channels1; c+=4) in1[c/4] = simd::float_4::load(inputs[IN1_INPUT].getVoltages(c)) * mult1; | for(int c=0; c<channels1; c+=4) in1[c/4] = simd::float_4::load(inputs[IN1_INPUT].getVoltages(c)) * mult1; | ||||
| for(i=0; i<channels1/4; i++) out[i] += in1[i]; // add only "real" channels. | for(i=0; i<channels1/4; i++) out[i] += in1[i]; // add only "real" channels. | ||||
| out[i] += simd::float_4(_mm_and_ps(in1[i].v, mask[channels1-4*i].v)); // make sure we zero out spurious channels | |||||
| out[i] += simd::float_4(_mm_and_ps(in1[i].v, channelMask[channels1-4*i].v)); // make sure we zero out spurious channels | |||||
| } | } | ||||
| if(inputs[IN2_INPUT].isConnected()) { | if(inputs[IN2_INPUT].isConnected()) { | ||||
| for(int c=0; c<channels2; c+=4) in2[c/4] = simd::float_4::load(inputs[IN2_INPUT].getVoltages(c)) * mult2; | for(int c=0; c<channels2; c+=4) in2[c/4] = simd::float_4::load(inputs[IN2_INPUT].getVoltages(c)) * mult2; | ||||
| for(i=0; i<channels2/4; i++) out[i] += in2[i]; | for(i=0; i<channels2/4; i++) out[i] += in2[i]; | ||||
| out[i] += simd::float_4(_mm_and_ps(in2[i].v, mask[channels2-4*i].v)); | |||||
| out[i] += simd::float_4(_mm_and_ps(in2[i].v, channelMask[channels2-4*i].v)); | |||||
| } | } | ||||
| if(inputs[IN3_INPUT].isConnected()) { | if(inputs[IN3_INPUT].isConnected()) { | ||||
| for(int c=0; c<channels3; c+=4) in3[c/4] = simd::float_4::load(inputs[IN3_INPUT].getVoltages(c)) * mult3; | for(int c=0; c<channels3; c+=4) in3[c/4] = simd::float_4::load(inputs[IN3_INPUT].getVoltages(c)) * mult3; | ||||
| for(i=0; i<channels3/4; i++) out[i] += in3[i]; | for(i=0; i<channels3/4; i++) out[i] += in3[i]; | ||||
| out[i] += simd::float_4(_mm_and_ps(in3[i].v, mask[channels3-4*i].v)); | |||||
| out[i] += simd::float_4(_mm_and_ps(in3[i].v, channelMask[channels3-4*i].v)); | |||||
| } | } | ||||
| if(inputs[IN4_INPUT].isConnected()) { | if(inputs[IN4_INPUT].isConnected()) { | ||||
| for(int c=0; c<channels4; c+=4) in4[c/4] = simd::float_4::load(inputs[IN4_INPUT].getVoltages(c)) * mult4; | for(int c=0; c<channels4; c+=4) in4[c/4] = simd::float_4::load(inputs[IN4_INPUT].getVoltages(c)) * mult4; | ||||
| for(i=0; i<channels4/4; i++) out[i] += in4[i]; | for(i=0; i<channels4/4; i++) out[i] += in4[i]; | ||||
| out[i] += simd::float_4(_mm_and_ps(in4[i].v, mask[channels4-4*i].v)); | |||||
| out[i] += simd::float_4(_mm_and_ps(in4[i].v, channelMask[channels4-4*i].v)); | |||||
| } | } | ||||
| @@ -1,4 +1,5 @@ | |||||
| #include "plugin.hpp" | #include "plugin.hpp" | ||||
| #include "simd_mask.hpp" | |||||
| static float shapeDelta(float delta, float tau, float shape) { | static float shapeDelta(float delta, float tau, float shape) { | ||||
| @@ -73,10 +74,18 @@ struct Rampage : Module { | |||||
| NUM_LIGHTS | NUM_LIGHTS | ||||
| }; | }; | ||||
| /* | |||||
| float out[2] = {}; | float out[2] = {}; | ||||
| bool gate[2] = {}; | bool gate[2] = {}; | ||||
| dsp::SchmittTrigger trigger[2]; | |||||
| dsp::PulseGenerator endOfCyclePulse[2]; | |||||
| */ | |||||
| simd::float_4 out[2][4]; | |||||
| simd::int32_4 gate[2][4]; // represent bool as integer: false = 0; true > o0 | |||||
| dsp::SchmittTrigger trigger[2, PORT_MAX_CHANNELS]; | |||||
| dsp::PulseGenerator endOfCyclePulse[2, PORT_MAX_CHANNELS]; | |||||
| ChannelMask channelMask; | |||||
| Rampage() { | Rampage() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
| @@ -93,12 +102,27 @@ struct Rampage : Module { | |||||
| configParam(FALL_B_PARAM, 0.0, 1.0, 0.0, "Ch 2 fall time"); | configParam(FALL_B_PARAM, 0.0, 1.0, 0.0, "Ch 2 fall time"); | ||||
| configParam(CYCLE_B_PARAM, 0.0, 1.0, 0.0, "Ch 2 cycle"); | configParam(CYCLE_B_PARAM, 0.0, 1.0, 0.0, "Ch 2 cycle"); | ||||
| configParam(BALANCE_PARAM, 0.0, 1.0, 0.5, "Balance"); | configParam(BALANCE_PARAM, 0.0, 1.0, 0.5, "Balance"); | ||||
| memset(out, 0, sizeof(out)); | |||||
| memset(gate, 0, sizeof(gate)); | |||||
| } | } | ||||
| void process(const ProcessArgs &args) override { | void process(const ProcessArgs &args) override { | ||||
| for (int c = 0; c < 2; c++) { | |||||
| float in = inputs[IN_A_INPUT + c].getVoltage(); | |||||
| if (trigger[c].process(params[TRIGG_A_PARAM + c].getValue() * 10.0 + inputs[TRIGG_A_INPUT + c].getVoltage() / 2.0)) { | |||||
| int channels_in_A[2]; | |||||
| int channels_in_B[2]; | |||||
| for (int part=0; part<2; part++) { | |||||
| channels_in_A[part] = inputs[IN_A_INPUT].getChannels() | |||||
| channels_in_B[part] = inputs[IN_B_INPUT].getChannels() | |||||
| } | |||||
| for (int part = 0; part < 2; part++) { | |||||
| simd::float_4 in[4]; | |||||
| load_input(inputs[IN_A_INPUT + part], in, channels_in_A[part]); | |||||
| if (trigger[part].process(params[TRIGG_A_PARAM + part].getValue() * 10.0 + inputs[TRIGG_A_INPUT + part].getVoltage() / 2.0)) { | |||||
| gate[c] = true; | gate[c] = true; | ||||
| } | } | ||||
| if (gate[c]) { | if (gate[c]) { | ||||
| @@ -0,0 +1,46 @@ | |||||
| #pragma once | |||||
| #include "rack.hpp" | |||||
| struct ChannelMask { | |||||
| rack::simd::float_4 mask[4]; | |||||
| ChannelMask() { | |||||
| __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); | |||||
| } | |||||
| }; | |||||
| ~ChannelMask() {}; | |||||
| inline const rack::simd::float_4 operator[](const int c) {return mask[c];} | |||||
| inline void apply(simd::float_4 *vec, int numChannels) { | |||||
| int c=numChannels/4; | |||||
| vec[c] = vec[c]&mask[numChannels-4*c]; | |||||
| } | |||||
| inline void apply_all(simd::float_4 *vec, int numChannels) { | |||||
| int c=numChannels/4; | |||||
| vec[c] = vec[c]&mask[numChannels-4*c]; | |||||
| for(int i=c+1; i<4; i++) vec[i] = simd::float_4(0.f); | |||||
| } | |||||
| }; | |||||
| 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; c<numChannels; c+=4) v[c/4] = simd::float_4::load(in.getVoltages(c)); | |||||
| } | |||||
| } | |||||