@@ -17,7 +17,7 @@ jobs: | |||||
config: | config: | ||||
- { | - { | ||||
name: Linux, | name: Linux, | ||||
os: ubuntu-latest, | |||||
os: ubuntu-16.04, | |||||
prepare-os: sudo apt install -y libglu-dev | 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 | # 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 | # see also https://vcvrack.com/manual/Manifest#version | ||||
if: startsWith(github.ref, 'refs/tags/v') | if: startsWith(github.ref, 'refs/tags/v') | ||||
runs-on: ubuntu-latest | |||||
runs-on: ubuntu-16.04 | |||||
needs: build | needs: build | ||||
steps: | steps: | ||||
- uses: actions/checkout@v2 | - uses: actions/checkout@v2 | ||||
@@ -1,6 +1,7 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "Common.hpp" | #include "Common.hpp" | ||||
#include "simd_input.hpp" | |||||
using simd::float_4; | |||||
template <typename T> | template <typename T> | ||||
static T clip4(T x) { | static T clip4(T x) { | ||||
@@ -54,126 +55,112 @@ struct ABC : Module { | |||||
configParam(C2_LEVEL_PARAM, -1.0, 1.0, 0.0, "C2 Level"); | 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 { | 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<float_4>(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 { | 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<float_4>(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 { | 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<float_4>(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 | // Set outputs | ||||
if (outputs[OUT1_OUTPUT].isConnected()) { | 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)); | 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]; | 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)); | out2[c / 4].store(outputs[OUT2_OUTPUT].getVoltages(c)); | ||||
} | } | ||||
@@ -182,7 +169,7 @@ struct ABC : Module { | |||||
float light_1; | float light_1; | ||||
float light_2; | float light_2; | ||||
if (channels_1 == 1) { | |||||
if (activeEngines1 == 1) { | |||||
light_1 = out1[0].s[0]; | light_1 = out1[0].s[0]; | ||||
lights[OUT1_LIGHT + 0].setSmoothBrightness(light_1 / 5.f, args.sampleTime); | lights[OUT1_LIGHT + 0].setSmoothBrightness(light_1 / 5.f, args.sampleTime); | ||||
lights[OUT1_LIGHT + 1].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); | lights[OUT1_LIGHT + 2].setBrightness(light_1); | ||||
} | } | ||||
if (channels_2 == 1) { | |||||
if (activeEngines2 == 1) { | |||||
light_2 = out2[0].s[0]; | light_2 = out2[0].s[0]; | ||||
lights[OUT2_LIGHT + 0].setSmoothBrightness(light_2 / 5.f, args.sampleTime); | lights[OUT2_LIGHT + 0].setSmoothBrightness(light_2 / 5.f, args.sampleTime); | ||||
lights[OUT2_LIGHT + 1].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 { | struct ABCWidget : ModuleWidget { | ||||
ABCWidget(ABC *module) { | |||||
ABCWidget(ABC* module) { | |||||
setModule(module); | setModule(module); | ||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ABC.svg"))); | setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ABC.svg"))); | ||||
@@ -239,4 +226,4 @@ struct ABCWidget : ModuleWidget { | |||||
}; | }; | ||||
Model *modelABC = createModel<ABC, ABCWidget>("ABC"); | |||||
Model* modelABC = createModel<ABC, ABCWidget>("ABC"); |
@@ -1,6 +1,5 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "Common.hpp" | #include "Common.hpp" | ||||
#include "simd_input.hpp" | |||||
struct DualAtenuverter : Module { | struct DualAtenuverter : Module { | ||||
enum ParamIds { | enum ParamIds { | ||||
@@ -34,7 +33,7 @@ struct DualAtenuverter : Module { | |||||
configParam(OFFSET2_PARAM, -10.0, 10.0, 0.0, "Ch 2 offset", " V"); | 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; | using simd::float_4; | ||||
float_4 out1[4]; | float_4 out1[4]; | ||||
@@ -52,10 +51,10 @@ struct DualAtenuverter : Module { | |||||
float offset2 = params[OFFSET2_PARAM].getValue(); | float offset2 = params[OFFSET2_PARAM].getValue(); | ||||
for (int c = 0; c < channels1; c += 4) { | 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<float_4>(c) * att1 + offset1, -10.f, 10.f); | |||||
} | } | ||||
for (int c = 0; c < channels2; c += 4) { | 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<float_4>(c) * att2 + offset2, -10.f, 10.f); | |||||
} | } | ||||
outputs[OUT1_OUTPUT].setChannels(channels1); | outputs[OUT1_OUTPUT].setChannels(channels1); | ||||
@@ -97,7 +96,7 @@ struct DualAtenuverter : Module { | |||||
struct DualAtenuverterWidget : ModuleWidget { | struct DualAtenuverterWidget : ModuleWidget { | ||||
DualAtenuverterWidget(DualAtenuverter *module) { | |||||
DualAtenuverterWidget(DualAtenuverter* module) { | |||||
setModule(module); | setModule(module); | ||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/DualAtenuverter.svg"))); | setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/DualAtenuverter.svg"))); | ||||
@@ -121,4 +120,4 @@ struct DualAtenuverterWidget : ModuleWidget { | |||||
}; | }; | ||||
Model *modelDualAtenuverter = createModel<DualAtenuverter, DualAtenuverterWidget>("DualAtenuverter"); | |||||
Model* modelDualAtenuverter = createModel<DualAtenuverter, DualAtenuverterWidget>("DualAtenuverter"); |
@@ -1,7 +1,8 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "simd_input.hpp" | |||||
#include "Common.hpp" | #include "Common.hpp" | ||||
using simd::float_4; | |||||
struct EvenVCO : Module { | struct EvenVCO : Module { | ||||
enum ParamIds { | enum ParamIds { | ||||
OCTAVE_PARAM, | OCTAVE_PARAM, | ||||
@@ -26,8 +27,8 @@ struct EvenVCO : Module { | |||||
NUM_OUTPUTS | 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 */ | /** The value of the last sync input */ | ||||
float sync = 0.0; | float sync = 0.0; | ||||
@@ -51,23 +52,14 @@ struct EvenVCO : Module { | |||||
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++) { | 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++) | for (int c = 0; c < PORT_MAX_CHANNELS; c++) | ||||
halfPhase[c] = false; | 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_pitch1 = inputs[PITCH1_INPUT].getChannels(); | ||||
int channels_pitch2 = inputs[PITCH2_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; | float pitch_0 = 1.f + std::round(params[OCTAVE_PARAM].getValue()) + params[TUNE_PARAM].getValue() / 12.f; | ||||
// Compute frequency, pitch is 1V/oct | // Compute frequency, pitch is 1V/oct | ||||
float_4 pitch[4]; | |||||
for (int c = 0; c < channels; c += 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()) { | 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<float_4>(c); | |||||
} | |||||
} | } | ||||
if (inputs[PITCH2_INPUT].isConnected()) { | 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<float_4>(c); | |||||
} | |||||
} | } | ||||
if (inputs[FM_INPUT].isConnected()) { | 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<float_4>(c) / 4.f; | |||||
} | |||||
} | } | ||||
float_4 freq[4]; | |||||
for (int c = 0; c < channels; c += 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] = dsp::FREQ_C4 * simd::pow(2.f, pitch[c / 4]); | ||||
freq[c / 4] = clamp(freq[c / 4], 0.f, 20000.f); | freq[c / 4] = clamp(freq[c / 4], 0.f, 20000.f); | ||||
} | } | ||||
// Pulse width | // Pulse width | ||||
float pw_0 = params[PWM_PARAM].getValue(); | float pw_0 = params[PWM_PARAM].getValue(); | ||||
float_4 pw[4]; | |||||
for (int c = 0; c < channels; c += 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()) { | 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<float_4>(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) { | 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); | 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 | // 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]; | oldPhase[c / 4] = phase[c / 4]; | ||||
phase[c / 4] += deltaPhase[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++) { | for (int c = 0; c < channels; c++) { | ||||
triSquareMinBlepOut[c / 4].s[c % 4] = triSquareMinBlep[c].process(); | triSquareMinBlepOut[c / 4].s[c % 4] = triSquareMinBlep[c].process(); | ||||
@@ -231,7 +246,7 @@ struct EvenVCO : Module { | |||||
struct EvenVCOWidget : ModuleWidget { | struct EvenVCOWidget : ModuleWidget { | ||||
EvenVCOWidget(EvenVCO *module) { | |||||
EvenVCOWidget(EvenVCO* module) { | |||||
setModule(module); | setModule(module); | ||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/EvenVCO.svg"))); | setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/EvenVCO.svg"))); | ||||
@@ -260,4 +275,4 @@ struct EvenVCOWidget : ModuleWidget { | |||||
}; | }; | ||||
Model *modelEvenVCO = createModel<EvenVCO, EvenVCOWidget>("EvenVCO"); | |||||
Model* modelEvenVCO = createModel<EvenVCO, EvenVCOWidget>("EvenVCO"); |
@@ -1,6 +1,7 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "Common.hpp" | #include "Common.hpp" | ||||
#include "simd_input.hpp" | |||||
using simd::float_4; | |||||
struct Mixer : Module { | struct Mixer : Module { | ||||
enum ParamIds { | enum ParamIds { | ||||
@@ -37,7 +38,7 @@ struct Mixer : Module { | |||||
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); | ||||
} | } | ||||
void process(const ProcessArgs &args) override { | |||||
void process(const ProcessArgs& args) override { | |||||
int channels1 = inputs[IN1_INPUT].getChannels(); | int channels1 = inputs[IN1_INPUT].getChannels(); | ||||
int channels2 = inputs[IN2_INPUT].getChannels(); | int channels2 = inputs[IN2_INPUT].getChannels(); | ||||
int channels3 = inputs[IN3_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, channels3); | ||||
out_channels = std::max(out_channels, channels4); | 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)); | std::memset(out, 0, sizeof(out)); | ||||
if (inputs[IN1_INPUT].isConnected()) { | if (inputs[IN1_INPUT].isConnected()) { | ||||
for (int c = 0; c < channels1; c += 4) | 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<float_4>(c) * mult1; | |||||
} | } | ||||
if (inputs[IN2_INPUT].isConnected()) { | if (inputs[IN2_INPUT].isConnected()) { | ||||
for (int c = 0; c < channels2; c += 4) | 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<float_4>(c) * mult2; | |||||
} | } | ||||
if (inputs[IN3_INPUT].isConnected()) { | if (inputs[IN3_INPUT].isConnected()) { | ||||
for (int c = 0; c < channels3; c += 4) | 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<float_4>(c) * mult3; | |||||
} | } | ||||
if (inputs[IN4_INPUT].isConnected()) { | if (inputs[IN4_INPUT].isConnected()) { | ||||
for (int c = 0; c < channels4; c += 4) | 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<float_4>(c) * mult4; | |||||
} | } | ||||
outputs[OUT1_OUTPUT].setChannels(out_channels); | outputs[OUT1_OUTPUT].setChannels(out_channels); | ||||
outputs[OUT2_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_NEG_LIGHT].setBrightness(0.0f); | ||||
lights[OUT_BLUE_LIGHT].setSmoothBrightness(light / 5.f, args.sampleTime); | lights[OUT_BLUE_LIGHT].setSmoothBrightness(light / 5.f, args.sampleTime); | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
struct MixerWidget : ModuleWidget { | struct MixerWidget : ModuleWidget { | ||||
MixerWidget(Mixer *module) { | |||||
MixerWidget(Mixer* module) { | |||||
setModule(module); | setModule(module); | ||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Mixer.svg"))); | setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Mixer.svg"))); | ||||
@@ -137,4 +135,4 @@ struct MixerWidget : ModuleWidget { | |||||
}; | }; | ||||
Model *modelMixer = createModel<Mixer, MixerWidget>("Mixer"); | |||||
Model* modelMixer = createModel<Mixer, MixerWidget>("Mixer"); |
@@ -1,16 +1,17 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "Common.hpp" | #include "Common.hpp" | ||||
#include "simd_input.hpp" | |||||
#include "PulseGenerator_4.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) { | 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); | return simd::crossfade(lin, log, -shape * 0.95f); | ||||
} | } | ||||
else { | else { | ||||
simd::float_4 exp = M_E * delta / tau; | |||||
float_4 exp = M_E * delta / tau; | |||||
return simd::crossfade(lin, exp, shape * 0.90f); | 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<simd::float_4> trigger_4[2][4]; | |||||
dsp::TSchmittTrigger<float_4> trigger_4[2][4]; | |||||
PulseGenerator_4 endOfCyclePulse[2][4]; | PulseGenerator_4 endOfCyclePulse[2][4]; | ||||
// ChannelMask channelMask; | // ChannelMask channelMask; | ||||
@@ -103,10 +104,10 @@ struct Rampage : Module { | |||||
std::memset(gate, 0, sizeof(gate)); | std::memset(gate, 0, sizeof(gate)); | ||||
} | } | ||||
void process(const ProcessArgs &args) override { | |||||
void process(const ProcessArgs& args) override { | |||||
int channels_in[2]; | int channels_in[2]; | ||||
int channels_trig[2]; | int channels_trig[2]; | ||||
int channels[2]; | |||||
int channels[2]; // the larger of in or trig (per-part) | |||||
// determine number of channels: | // determine number of channels: | ||||
@@ -122,25 +123,25 @@ struct Rampage : Module { | |||||
outputs[FALLING_A_OUTPUT + part].setChannels(channels[part]); | outputs[FALLING_A_OUTPUT + part].setChannels(channels[part]); | ||||
outputs[EOC_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[COMPARATOR_OUTPUT].setChannels(channels_max); | ||||
outputs[MIN_OUTPUT].setChannels(channels_max); | outputs[MIN_OUTPUT].setChannels(channels_max); | ||||
outputs[MAX_OUTPUT].setChannels(channels_max); | outputs[MAX_OUTPUT].setChannels(channels_max); | ||||
// loop over two parts of Rampage: | // loop over two parts of Rampage: | ||||
for (int part = 0; part < 2; part++) { | 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: | // get parameters: | ||||
float shape = params[SHAPE_A_PARAM + part].getValue(); | float shape = params[SHAPE_A_PARAM + part].getValue(); | ||||
float minTime; | float minTime; | ||||
switch ((int) params[RANGE_A_PARAM + part].getValue()) { | switch ((int) params[RANGE_A_PARAM + part].getValue()) { | ||||
@@ -155,91 +156,142 @@ struct Rampage : Module { | |||||
break; | 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) { | for (int c = 0; c < channels[part]; c += 4) { | ||||
riseCV[c / 4] = param_rise; | riseCV[c / 4] = param_rise; | ||||
fallCV[c / 4] = param_fall; | fallCV[c / 4] = param_fall; | ||||
cycle[c / 4] = param_cycle; | cycle[c / 4] = param_cycle; | ||||
in_trig[c / 4] = param_trig; | in_trig[c / 4] = param_trig; | ||||
} | } | ||||
// read inputs: | // read inputs: | ||||
if (inputs[IN_A_INPUT + part].isConnected()) { | 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_<A,B>_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<float_4>(c); | |||||
} | |||||
} | } | ||||
else { | else { | ||||
std::memset(in, 0, sizeof(in)); | std::memset(in, 0, sizeof(in)); | ||||
} | } | ||||
if (inputs[TRIGG_A_INPUT + part].isConnected()) { | 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_<A,B>_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<float_4>(c); | |||||
} | |||||
} | } | ||||
if (inputs[EXP_CV_A_INPUT + part].isConnected()) { | 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_<A,B>_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<float_4>(c); | |||||
} | |||||
for (int c = 0; c < channels[part]; c += 4) { | for (int c = 0; c < channels[part]; c += 4) { | ||||
riseCV[c / 4] -= expCV[c / 4]; | riseCV[c / 4] -= expCV[c / 4]; | ||||
fallCV[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_<A,B>_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<float_4>(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<float_4>(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<float_4>(c); | |||||
} | |||||
// start processing: | |||||
for (int c = 0; c < channels[part]; c += 4) { | for (int c = 0; c < channels[part]; c += 4) { | ||||
// process SchmittTriggers | // 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 | // 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 = 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; | 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); | 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]); | 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)); | 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_falling.store(outputs[FALLING_A_OUTPUT + part].getVoltages(c)); | ||||
out_EOC.store(outputs[EOC_A_OUTPUT + part].getVoltages(c)); | out_EOC.store(outputs[EOC_A_OUTPUT + part].getVoltages(c)); | ||||
} // for(int c, ...) | } // for(int c, ...) | ||||
if (channels[part] == 1) { | if (channels[part] == 1) { | ||||
@@ -281,17 +332,17 @@ struct Rampage : Module { | |||||
for (int c = 0; c < channels_max; c += 4) { | 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) | if (balance < 0.5) | ||||
b *= 2.0f * balance; | b *= 2.0f * balance; | ||||
else if (balance > 0.5) | else if (balance > 0.5) | ||||
a *= 2.0f * (1.0 - balance); | 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)); | comp.store(outputs[COMPARATOR_OUTPUT].getVoltages(c)); | ||||
out_min.store(outputs[MIN_OUTPUT].getVoltages(c)); | out_min.store(outputs[MIN_OUTPUT].getVoltages(c)); | ||||
@@ -325,10 +376,8 @@ struct Rampage : Module { | |||||
}; | }; | ||||
struct RampageWidget : ModuleWidget { | struct RampageWidget : ModuleWidget { | ||||
RampageWidget(Rampage *module) { | |||||
RampageWidget(Rampage* module) { | |||||
setModule(module); | setModule(module); | ||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Rampage.svg"))); | setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Rampage.svg"))); | ||||
@@ -389,4 +438,4 @@ struct RampageWidget : ModuleWidget { | |||||
}; | }; | ||||
Model *modelRampage = createModel<Rampage, RampageWidget>("Rampage"); | |||||
Model* modelRampage = createModel<Rampage, RampageWidget>("Rampage"); |
@@ -1,6 +1,7 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "Common.hpp" | #include "Common.hpp" | ||||
#include "simd_input.hpp" | |||||
using simd::float_4; | |||||
struct SlewLimiter : Module { | struct SlewLimiter : Module { | ||||
enum ParamIds { | enum ParamIds { | ||||
@@ -20,7 +21,7 @@ struct SlewLimiter : Module { | |||||
NUM_OUTPUTS | NUM_OUTPUTS | ||||
}; | }; | ||||
simd::float_4 out[4]; | |||||
float_4 out[4]; | |||||
SlewLimiter() { | SlewLimiter() { | ||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); | ||||
@@ -31,14 +32,14 @@ struct SlewLimiter : Module { | |||||
memset(out, 0, sizeof(out)); | 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 | // minimum and std::maximum slopes in volts per second | ||||
const float slewMin = 0.1; | const float slewMin = 0.1; | ||||
@@ -46,32 +47,45 @@ 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; | ||||
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<float_4>(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<float_4>(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<float_4>(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; | riseCV[c / 4] += param_rise; | ||||
fallCV[c / 4] += param_fall; | 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; | 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] += 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]); | 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 { | struct SlewLimiterWidget : ModuleWidget { | ||||
SlewLimiterWidget(::SlewLimiter *module) { | |||||
SlewLimiterWidget(SlewLimiter* module) { | |||||
setModule(module); | setModule(module); | ||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/SlewLimiter.svg"))); | 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"); |
@@ -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)); | |||||
} | |||||
} |