Signed-off-by: hemmer <915048+hemmer@users.noreply.github.com>tags/v1.1.0^2
@@ -33,7 +33,8 @@ | |||||
"tags": [ | "tags": [ | ||||
"Ring Modulator", | "Ring Modulator", | ||||
"Attenuator", | "Attenuator", | ||||
"Dual" | |||||
"Dual", | |||||
"Polyphonic" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -47,7 +48,8 @@ | |||||
"slug": "Mixer", | "slug": "Mixer", | ||||
"name": "Mixer", | "name": "Mixer", | ||||
"tags": [ | "tags": [ | ||||
"Mixer" | |||||
"Mixer", | |||||
"Polyphonic" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -55,7 +57,8 @@ | |||||
"name": "Slew Limiter", | "name": "Slew Limiter", | ||||
"tags": [ | "tags": [ | ||||
"Slew Limiter", | "Slew Limiter", | ||||
"Envelope Follower" | |||||
"Envelope Follower", | |||||
"Polyphonic" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -63,7 +66,8 @@ | |||||
"name": "Dual Atenuverter", | "name": "Dual Atenuverter", | ||||
"tags": [ | "tags": [ | ||||
"Attenuator", | "Attenuator", | ||||
"Dual" | |||||
"Dual", | |||||
"Polyphonic" | |||||
] | ] | ||||
} | } | ||||
] | ] |
@@ -1,5 +1,6 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#define MAX(a,b) (a>b)?a:b | |||||
static float clip(float x) { | 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)); | / (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) { | static float exponentialBipolar80Pade_5_4(float x) { | ||||
return (0.109568*x + 0.281588*std::pow(x, 3) + 0.133841*std::pow(x, 5)) | 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)); | / (1. - 0.630374*std::pow(x, 2) + 0.166271*std::pow(x, 4)); | ||||
@@ -44,41 +65,156 @@ struct ABC : Module { | |||||
NUM_LIGHTS | NUM_LIGHTS | ||||
}; | }; | ||||
simd::float_4 mask[4]; | |||||
ABC() { | ABC() { | ||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
configParam(B1_LEVEL_PARAM, -1.0, 1.0, 0.0, "B1 Level"); | 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(C1_LEVEL_PARAM, -1.0, 1.0, 0.0, "C1 Level"); | ||||
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)); | |||||
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; 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 { | ||||
float a1 = inputs[A1_INPUT].getVoltage(); | |||||
float b1 = inputs[B1_INPUT].getNormalVoltage(5.f) * 2.f*exponentialBipolar80Pade_5_4(params[B1_LEVEL_PARAM].getValue()); | |||||
float c1 = inputs[C1_INPUT].getNormalVoltage(10.f) * exponentialBipolar80Pade_5_4(params[C1_LEVEL_PARAM].getValue()); | |||||
float out1 = a1 * b1 / 5.f + c1; | |||||
float a2 = inputs[A2_INPUT].getVoltage(); | |||||
float b2 = inputs[B2_INPUT].getNormalVoltage(5.f) * 2.f*exponentialBipolar80Pade_5_4(params[B2_LEVEL_PARAM].getValue()); | |||||
float c2 = inputs[C2_INPUT].getNormalVoltage(10.f) * exponentialBipolar80Pade_5_4(params[C2_LEVEL_PARAM].getValue()); | |||||
float out2 = a2 * b2 / 5.f + c2; | |||||
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_A1 = inputs[A1_INPUT].getChannels(); | |||||
int channels_A2 = inputs[A2_INPUT].getChannels(); | |||||
int channels_B1 = inputs[B1_INPUT].getChannels(); | |||||
int channels_B2 = inputs[B2_INPUT].getChannels(); | |||||
int channels_C1 = inputs[C1_INPUT].getChannels(); | |||||
int channels_C2 = inputs[C2_INPUT].getChannels(); | |||||
int channels_1 = 1; | |||||
channels_1 = MAX(channels_1, channels_A1); | |||||
channels_1 = MAX(channels_1, channels_B1); | |||||
channels_1 = MAX(channels_1, channels_C1); | |||||
int channels_2 = channels_1; | |||||
channels_2 = MAX(channels_2, channels_A2); | |||||
channels_2 = MAX(channels_2, channels_B2); | |||||
channels_2 = MAX(channels_2, channels_C2); | |||||
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_B2 = (2.f/5.f)*exponentialBipolar80Pade_5_4(params[B2_LEVEL_PARAM].getValue()); | |||||
float mult_C2 = exponentialBipolar80Pade_5_4(params[C2_LEVEL_PARAM].getValue()); | |||||
load_input(inputs[A1_INPUT], a1, channels_A1); | |||||
crop_channels(a1, channels_1); | |||||
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] = b1[c/4] * simd::float_4(mult_B1); | |||||
} else { | |||||
for(int c=0; c<channels_1; c+=4) b1[c/4] = simd::float_4(5.f*mult_B1); | |||||
} | |||||
crop_channels(b1, channels_1); | |||||
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] = c1[c/4] * simd::float_4(mult_C1); | |||||
} else { | |||||
for(int c=0; c<channels_1; c+=4) c1[c/4] = simd::float_4(10.f*mult_C1); | |||||
} | |||||
crop_channels(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]); | |||||
load_input(inputs[A1_INPUT], a1, channels_A1); | |||||
crop_channels(a1, channels_1); | |||||
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] = b2[c/4] * simd::float_4(mult_B2); | |||||
} else { | |||||
for(int c=0; c<channels_2; c+=4) b2[c/4] = simd::float_4(5.f*mult_B2); | |||||
} | |||||
crop_channels(b2, channels_2); | |||||
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] = 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); | |||||
} | |||||
crop_channels(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]); | |||||
// Set outputs | // Set outputs | ||||
if (outputs[OUT1_OUTPUT].isConnected()) { | if (outputs[OUT1_OUTPUT].isConnected()) { | ||||
outputs[OUT1_OUTPUT].setVoltage(clip(out1 / 10.f) * 10.f); | |||||
outputs[OUT1_OUTPUT].setChannels(channels_1); | |||||
for(int c=0; c<channels_1; c+=4) out1[c/4].store(outputs[OUT1_OUTPUT].getVoltages(c)); | |||||
} | } | ||||
else { | else { | ||||
out2 += out1; | |||||
for(int c=0; c<channels_1; c+=4) out2[c/4] += out1[c/4]; | |||||
} | } | ||||
if (outputs[OUT2_OUTPUT].isConnected()) { | if (outputs[OUT2_OUTPUT].isConnected()) { | ||||
outputs[OUT2_OUTPUT].setVoltage(clip(out2 / 10.f) * 10.f); | |||||
outputs[OUT2_OUTPUT].setChannels(channels_1); | |||||
for(int c=0; c<channels_1; c+=4) out2[c/4].store(outputs[OUT2_OUTPUT].getVoltages(c)); | |||||
} | } | ||||
// Lights | // Lights | ||||
lights[OUT1_LIGHT + 0].setSmoothBrightness(out1 / 5.f, args.sampleTime); | |||||
lights[OUT1_LIGHT + 1].setSmoothBrightness(-out1 / 5.f, args.sampleTime); | |||||
lights[OUT2_LIGHT + 0].setSmoothBrightness(out2 / 5.f, args.sampleTime); | |||||
lights[OUT2_LIGHT + 1].setSmoothBrightness(-out2 / 5.f, args.sampleTime); | |||||
float light_1; | |||||
float light_2; | |||||
if(channels_1==1) { | |||||
light_1 = out1[0].s[0]; | |||||
} else { | |||||
light_1 = outputs[OUT1_OUTPUT].getVoltageSum(); | |||||
} | |||||
lights[OUT1_LIGHT + 0].setSmoothBrightness(light_1 / 5.f, args.sampleTime); | |||||
lights[OUT1_LIGHT + 1].setSmoothBrightness(-light_1 / 5.f, args.sampleTime); | |||||
if(channels_2==1) { | |||||
light_2 = out2[0].s[0]; | |||||
} else { | |||||
light_2 = outputs[OUT2_OUTPUT].getVoltageSum(); | |||||
} | |||||
lights[OUT2_LIGHT + 0].setSmoothBrightness(light_2 / 5.f, args.sampleTime); | |||||
lights[OUT2_LIGHT + 1].setSmoothBrightness(-light_2 / 5.f, args.sampleTime); | |||||
} | } | ||||
}; | }; | ||||
@@ -36,17 +36,36 @@ struct DualAtenuverter : Module { | |||||
} | } | ||||
void process(const ProcessArgs &args) override { | void process(const ProcessArgs &args) override { | ||||
float out1 = inputs[IN1_INPUT].getVoltage() * params[ATEN1_PARAM].getValue() + params[OFFSET1_PARAM].getValue(); | |||||
float out2 = inputs[IN2_INPUT].getVoltage() * params[ATEN2_PARAM].getValue() + params[OFFSET2_PARAM].getValue(); | |||||
out1 = clamp(out1, -10.f, 10.f); | |||||
out2 = clamp(out2, -10.f, 10.f); | |||||
outputs[OUT1_OUTPUT].setVoltage(out1); | |||||
outputs[OUT2_OUTPUT].setVoltage(out2); | |||||
lights[OUT1_POS_LIGHT].setSmoothBrightness(out1 / 5.f, args.sampleTime); | |||||
lights[OUT1_NEG_LIGHT].setSmoothBrightness(-out1 / 5.f, args.sampleTime); | |||||
lights[OUT2_POS_LIGHT].setSmoothBrightness(out2 / 5.f, args.sampleTime); | |||||
lights[OUT2_NEG_LIGHT].setSmoothBrightness(-out2 / 5.f, args.sampleTime); | |||||
simd::float_4 out1[4]; | |||||
simd::float_4 out2[4]; | |||||
int channels1 = inputs[IN1_INPUT].getChannels(); channels1 = channels1>0?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); | |||||
} | } | ||||
}; | }; | ||||
@@ -1,5 +1,6 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#define MAX(a,b) (a>b)?a:b | |||||
struct EvenVCO : Module { | struct EvenVCO : Module { | ||||
enum ParamIds { | enum ParamIds { | ||||
@@ -47,11 +48,25 @@ struct EvenVCO : Module { | |||||
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"); | ||||
} | } | ||||
void process(const ProcessArgs &args) override { | void process(const ProcessArgs &args) override { | ||||
// Compute frequency, pitch is 1V/oct | // 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[PITCH1_INPUT].getVoltage() + inputs[PITCH2_INPUT].getVoltage(); | ||||
pitch += inputs[FM_INPUT].getVoltage() / 4.f; | pitch += inputs[FM_INPUT].getVoltage() / 4.f; | ||||
float freq = dsp::FREQ_C4 * std::pow(2.f, pitch); | float freq = dsp::FREQ_C4 * std::pow(2.f, pitch); | ||||
@@ -1,5 +1,8 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#define MAX(a,b) (a>b)?a:b | |||||
#define MIN(a,b) (a<b)?a:b | |||||
struct Mixer : Module { | struct Mixer : Module { | ||||
enum ParamIds { | enum ParamIds { | ||||
@@ -27,25 +30,103 @@ struct Mixer : Module { | |||||
NUM_LIGHTS | NUM_LIGHTS | ||||
}; | }; | ||||
simd::float_4 mask[4]; | |||||
simd::float_4 minus_one; | |||||
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); | ||||
configParam(CH2_PARAM, 0.0, 1.0, 0.0, "Ch 2 level", "%", 0, 100); | configParam(CH2_PARAM, 0.0, 1.0, 0.0, "Ch 2 level", "%", 0, 100); | ||||
configParam(CH3_PARAM, 0.0, 1.0, 0.0, "Ch 3 level", "%", 0, 100); | configParam(CH3_PARAM, 0.0, 1.0, 0.0, "Ch 3 level", "%", 0, 100); | ||||
configParam(CH4_PARAM, 0.0, 1.0, 0.0, "Ch 4 level", "%", 0, 100); | configParam(CH4_PARAM, 0.0, 1.0, 0.0, "Ch 4 level", "%", 0, 100); | ||||
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); | |||||
} | |||||
} | } | ||||
void process(const ProcessArgs &args) override { | void process(const ProcessArgs &args) override { | ||||
float in1 = inputs[IN1_INPUT].getVoltage() * params[CH1_PARAM].getValue(); | |||||
float in2 = inputs[IN2_INPUT].getVoltage() * params[CH2_PARAM].getValue(); | |||||
float in3 = inputs[IN3_INPUT].getVoltage() * params[CH3_PARAM].getValue(); | |||||
float in4 = inputs[IN4_INPUT].getVoltage() * params[CH4_PARAM].getValue(); | |||||
float out = in1 + in2 + in3 + in4; | |||||
outputs[OUT1_OUTPUT].setVoltage(out); | |||||
outputs[OUT2_OUTPUT].setVoltage(-out); | |||||
int i; | |||||
int channels1 = inputs[IN1_INPUT].getChannels(); | |||||
int channels2 = inputs[IN2_INPUT].getChannels(); | |||||
int channels3 = inputs[IN3_INPUT].getChannels(); | |||||
int channels4 = inputs[IN4_INPUT].getChannels(); | |||||
int out_channels = 1; | |||||
out_channels = MAX(out_channels, channels1); | |||||
out_channels = MAX(out_channels, channels2); | |||||
out_channels = MAX(out_channels, channels3); | |||||
out_channels = 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()); | |||||
simd::float_4 in1[4]; | |||||
simd::float_4 in2[4]; | |||||
simd::float_4 in3[4]; | |||||
simd::float_4 in4[4]; | |||||
simd::float_4 out[4]; | |||||
out[0] = simd::float_4(0.f); | |||||
out[1] = simd::float_4(0.f); | |||||
out[2] = simd::float_4(0.f); | |||||
out[3] = simd::float_4(0.f); | |||||
if(inputs[IN1_INPUT].isConnected()) { | |||||
// this also loads some spurious channels into in1[] | |||||
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. | |||||
out[i] += simd::float_4(_mm_and_ps(in1[i].v, mask[channels1-4*i].v)); // make sure we zero out spurious channels | |||||
} | |||||
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(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)); | |||||
} | |||||
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(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)); | |||||
} | |||||
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(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)); | |||||
} | |||||
outputs[OUT1_OUTPUT].setChannels(out_channels); | |||||
outputs[OUT2_OUTPUT].setChannels(out_channels); | |||||
for(int c=0; c<out_channels; c+=4) { | |||||
out[c / 4].store(outputs[OUT1_OUTPUT].getVoltages(c)); | |||||
out[c / 4] *= minus_one; | |||||
out[c / 4].store(outputs[OUT2_OUTPUT].getVoltages(c)); | |||||
} | |||||
/* | |||||
lights[OUT_POS_LIGHT].setSmoothBrightness(out / 5.f, args.sampleTime); | lights[OUT_POS_LIGHT].setSmoothBrightness(out / 5.f, args.sampleTime); | ||||
lights[OUT_NEG_LIGHT].setSmoothBrightness(-out / 5.f, args.sampleTime); | lights[OUT_NEG_LIGHT].setSmoothBrightness(-out / 5.f, args.sampleTime); | ||||
*/ | |||||
} | } | ||||
}; | }; | ||||
@@ -19,17 +19,21 @@ struct SlewLimiter : Module { | |||||
NUM_OUTPUTS | NUM_OUTPUTS | ||||
}; | }; | ||||
float out = 0.0; | |||||
float out[PORT_MAX_CHANNELS]; | |||||
SlewLimiter() { | SlewLimiter() { | ||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | ||||
configParam(SHAPE_PARAM, 0.0, 1.0, 0.0, "Shape"); | configParam(SHAPE_PARAM, 0.0, 1.0, 0.0, "Shape"); | ||||
configParam(RISE_PARAM, 0.0, 1.0, 0.0, "Rise time"); | configParam(RISE_PARAM, 0.0, 1.0, 0.0, "Rise time"); | ||||
configParam(FALL_PARAM, 0.0, 1.0, 0.0, "Fall time"); | configParam(FALL_PARAM, 0.0, 1.0, 0.0, "Fall time"); | ||||
memset(out, 0, sizeof(out)); | |||||
} | } | ||||
void process(const ProcessArgs &args) override { | void process(const ProcessArgs &args) override { | ||||
float in = inputs[IN_INPUT].getVoltage(); | |||||
int channels = inputs[IN_INPUT].getChannels(); | |||||
float shape = params[SHAPE_PARAM].getValue(); | float shape = params[SHAPE_PARAM].getValue(); | ||||
// minimum and maximum slopes in volts per second | // minimum and maximum slopes in volts per second | ||||
@@ -38,24 +42,36 @@ struct SlewLimiter : Module { | |||||
// Amount of extra slew per voltage difference | // Amount of extra slew per voltage difference | ||||
const float shapeScale = 1/10.f; | const float shapeScale = 1/10.f; | ||||
// Rise | |||||
if (in > 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<channels; c++) { | |||||
float in = inputs[IN_INPUT].getVoltage(c); | |||||
// Rise | |||||
if (in > 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); | |||||
} | } | ||||
}; | }; | ||||
@@ -65,8 +65,8 @@ struct SpringReverb : Module { | |||||
} | } | ||||
void process(const ProcessArgs &args) override { | 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 levelScale = 0.030; | ||||
const float levelBase = 25.0; | const float levelBase = 25.0; | ||||
float level1 = levelScale * dsp::exponentialBipolar(levelBase, params[LEVEL1_PARAM].getValue()) * inputs[CV1_INPUT].getNormalVoltage(10.0) / 10.0; | float level1 = levelScale * dsp::exponentialBipolar(levelBase, params[LEVEL1_PARAM].getValue()) * inputs[CV1_INPUT].getNormalVoltage(10.0) / 10.0; | ||||