Browse Source

Optimise VCO

We only need to do processing for wave types/outputs that are actually
connected.
pull/123/head
rleathart 4 years ago
parent
commit
127434ec9a
1 changed files with 92 additions and 57 deletions
  1. +92
    -57
      src/VCO.cpp

+ 92
- 57
src/VCO.cpp View File

@@ -24,6 +24,13 @@ T expCurve(T x) {
return (3 + x * (-13 + 5 * x)) / (3 + 2 * x); return (3 + x * (-13 + 5 * x)) / (3 + 2 * x);
} }


enum WaveIds {
SIN_WAVE = 1 << 0,
TRI_WAVE = 1 << 1,
SAW_WAVE = 1 << 2,
SQR_WAVE = 1 << 3,
ALL_WAVE = 0xffffffff
};


template <int OVERSAMPLE, int QUALITY, typename T> template <int OVERSAMPLE, int QUALITY, typename T>
struct VoltageControlledOscillator { struct VoltageControlledOscillator {
@@ -60,7 +67,10 @@ struct VoltageControlledOscillator {
this->pulseWidth = simd::clamp(pulseWidth, pwMin, 1.f - pwMin); this->pulseWidth = simd::clamp(pulseWidth, pwMin, 1.f - pwMin);
} }


void process(float deltaTime, T syncValue) {
void process(float deltaTime, T syncValue, int enabledWaves) {
// Do nothing if there aren't any waves to process
if (!enabledWaves) return;

// Advance phase // Advance phase
T deltaPhase = simd::clamp(freq * deltaTime, 1e-6f, 0.35f); T deltaPhase = simd::clamp(freq * deltaTime, 1e-6f, 0.35f);
if (soft) { if (soft) {
@@ -75,45 +85,49 @@ struct VoltageControlledOscillator {
// Wrap phase // Wrap phase
phase -= simd::floor(phase); phase -= simd::floor(phase);


// Jump sqr when crossing 0, or 1 if backwards
T wrapPhase = (syncDirection == -1.f) & 1.f;
T wrapCrossing = (wrapPhase - (phase - deltaPhase)) / deltaPhase;
int wrapMask = simd::movemask((0 < wrapCrossing) & (wrapCrossing <= 1.f));
if (wrapMask) {
for (int i = 0; i < channels; i++) {
if (wrapMask & (1 << i)) {
T mask = simd::movemaskInverse<T>(1 << i);
float p = wrapCrossing[i] - 1.f;
T x = mask & (2.f * syncDirection);
sqrMinBlep.insertDiscontinuity(p, x);
if (enabledWaves & SQR_WAVE) {
// Jump sqr when crossing 0, or 1 if backwards
T wrapPhase = (syncDirection == -1.f) & 1.f;
T wrapCrossing = (wrapPhase - (phase - deltaPhase)) / deltaPhase;
int wrapMask = simd::movemask((0 < wrapCrossing) & (wrapCrossing <= 1.f));
if (wrapMask) {
for (int i = 0; i < channels; i++) {
if (wrapMask & (1 << i)) {
T mask = simd::movemaskInverse<T>(1 << i);
float p = wrapCrossing[i] - 1.f;
T x = mask & (2.f * syncDirection);
sqrMinBlep.insertDiscontinuity(p, x);
}
} }
} }
}


// Jump sqr when crossing `pulseWidth`
T pulseCrossing = (pulseWidth - (phase - deltaPhase)) / deltaPhase;
int pulseMask = simd::movemask((0 < pulseCrossing) & (pulseCrossing <= 1.f));
if (pulseMask) {
for (int i = 0; i < channels; i++) {
if (pulseMask & (1 << i)) {
T mask = simd::movemaskInverse<T>(1 << i);
float p = pulseCrossing[i] - 1.f;
T x = mask & (-2.f * syncDirection);
sqrMinBlep.insertDiscontinuity(p, x);
// Jump sqr when crossing `pulseWidth`
T pulseCrossing = (pulseWidth - (phase - deltaPhase)) / deltaPhase;
int pulseMask = simd::movemask((0 < pulseCrossing) & (pulseCrossing <= 1.f));
if (pulseMask) {
for (int i = 0; i < channels; i++) {
if (pulseMask & (1 << i)) {
T mask = simd::movemaskInverse<T>(1 << i);
float p = pulseCrossing[i] - 1.f;
T x = mask & (-2.f * syncDirection);
sqrMinBlep.insertDiscontinuity(p, x);
}
} }
} }
} }


// Jump saw when crossing 0.5
T halfCrossing = (0.5f - (phase - deltaPhase)) / deltaPhase;
int halfMask = simd::movemask((0 < halfCrossing) & (halfCrossing <= 1.f));
if (halfMask) {
for (int i = 0; i < channels; i++) {
if (halfMask & (1 << i)) {
T mask = simd::movemaskInverse<T>(1 << i);
float p = halfCrossing[i] - 1.f;
T x = mask & (-2.f * syncDirection);
sawMinBlep.insertDiscontinuity(p, x);
if (enabledWaves & SAW_WAVE) {
// Jump saw when crossing 0.5
T halfCrossing = (0.5f - (phase - deltaPhase)) / deltaPhase;
int halfMask = simd::movemask((0 < halfCrossing) & (halfCrossing <= 1.f));
if (halfMask) {
for (int i = 0; i < channels; i++) {
if (halfMask & (1 << i)) {
T mask = simd::movemaskInverse<T>(1 << i);
float p = halfCrossing[i] - 1.f;
T x = mask & (-2.f * syncDirection);
sawMinBlep.insertDiscontinuity(p, x);
}
} }
} }
} }
@@ -154,26 +168,34 @@ struct VoltageControlledOscillator {
} }


// Square // Square
sqrValue = sqr(phase);
sqrValue += sqrMinBlep.process();

if (analog) {
sqrFilter.setCutoffFreq(20.f * deltaTime);
sqrFilter.process(sqrValue);
sqrValue = sqrFilter.highpass() * 0.95f;
if (enabledWaves & SQR_WAVE) {
sqrValue = sqr(phase);
sqrValue += sqrMinBlep.process();

if (analog) {
sqrFilter.setCutoffFreq(20.f * deltaTime);
sqrFilter.process(sqrValue);
sqrValue = sqrFilter.highpass() * 0.95f;
}
} }


// Saw // Saw
sawValue = saw(phase);
sawValue += sawMinBlep.process();
if (enabledWaves & SAW_WAVE) {
sawValue = saw(phase);
sawValue += sawMinBlep.process();
}


// Tri // Tri
triValue = tri(phase);
triValue += triMinBlep.process();
if (enabledWaves & TRI_WAVE) {
triValue = tri(phase);
triValue += triMinBlep.process();
}


// Sin // Sin
sinValue = sin(phase);
sinValue += sinMinBlep.process();
if (enabledWaves & SIN_WAVE) {
sinValue = sin(phase);
sinValue += sinMinBlep.process();
}
} }


T sin(T phase) { T sin(T phase) {
@@ -291,12 +313,25 @@ struct VCO : Module {
} }


void process(const ProcessArgs& args) override { void process(const ProcessArgs& args) override {
int enabledWaves = 0; // Need to use int here becuase C++
if (outputs[SIN_OUTPUT].isConnected())
enabledWaves |= SIN_WAVE;
if (outputs[TRI_OUTPUT].isConnected())
enabledWaves |= TRI_WAVE;
if (outputs[SAW_OUTPUT].isConnected())
enabledWaves |= SAW_WAVE;
if (outputs[SQR_OUTPUT].isConnected())
enabledWaves |= SQR_WAVE;

if (!enabledWaves) return;

float freqParam = params[FREQ_PARAM].getValue() / 12.f; float freqParam = params[FREQ_PARAM].getValue() / 12.f;
freqParam += dsp::quadraticBipolar(params[FINE_PARAM].getValue()) * 3.f / 12.f; freqParam += dsp::quadraticBipolar(params[FINE_PARAM].getValue()) * 3.f / 12.f;
float fmParam = dsp::quadraticBipolar(params[FM_PARAM].getValue()); float fmParam = dsp::quadraticBipolar(params[FM_PARAM].getValue());


int channels = std::max(inputs[PITCH_INPUT].getChannels(), 1); int channels = std::max(inputs[PITCH_INPUT].getChannels(), 1);



for (int c = 0; c < channels; c += 4) { for (int c = 0; c < channels; c += 4) {
auto* oscillator = &oscillators[c / 4]; auto* oscillator = &oscillators[c / 4];
oscillator->channels = std::min(channels - c, 4); oscillator->channels = std::min(channels - c, 4);
@@ -312,7 +347,7 @@ struct VCO : Module {
oscillator->setPulseWidth(params[PW_PARAM].getValue() + params[PWM_PARAM].getValue() * inputs[PW_INPUT].getPolyVoltageSimd<float_4>(c) / 10.f); oscillator->setPulseWidth(params[PW_PARAM].getValue() + params[PWM_PARAM].getValue() * inputs[PW_INPUT].getPolyVoltageSimd<float_4>(c) / 10.f);


oscillator->syncEnabled = inputs[SYNC_INPUT].isConnected(); oscillator->syncEnabled = inputs[SYNC_INPUT].isConnected();
oscillator->process(args.sampleTime, inputs[SYNC_INPUT].getPolyVoltageSimd<float_4>(c));
oscillator->process(args.sampleTime, inputs[SYNC_INPUT].getPolyVoltageSimd<float_4>(c), enabledWaves);


// Set output // Set output
if (outputs[SIN_OUTPUT].isConnected()) if (outputs[SIN_OUTPUT].isConnected())
@@ -423,6 +458,8 @@ struct VCO2 : Module {
} }


void process(const ProcessArgs& args) override { void process(const ProcessArgs& args) override {
if (!outputs[OUT_OUTPUT].isConnected()) return;

float freqParam = params[FREQ_PARAM].getValue() / 12.f; float freqParam = params[FREQ_PARAM].getValue() / 12.f;
float fmParam = dsp::quadraticBipolar(params[FM_PARAM].getValue()); float fmParam = dsp::quadraticBipolar(params[FM_PARAM].getValue());
float waveParam = params[WAVE_PARAM].getValue(); float waveParam = params[WAVE_PARAM].getValue();
@@ -440,18 +477,16 @@ struct VCO2 : Module {
oscillator->setPitch(pitch); oscillator->setPitch(pitch);


oscillator->syncEnabled = inputs[SYNC_INPUT].isConnected(); oscillator->syncEnabled = inputs[SYNC_INPUT].isConnected();
oscillator->process(args.sampleTime, inputs[SYNC_INPUT].getPolyVoltageSimd<float_4>(c));
oscillator->process(args.sampleTime, inputs[SYNC_INPUT].getPolyVoltageSimd<float_4>(c), ALL_WAVE);


// Outputs // Outputs
if (outputs[OUT_OUTPUT].isConnected()) {
float_4 wave = simd::clamp(waveParam + inputs[WAVE_INPUT].getPolyVoltageSimd<float_4>(c) / 10.f * 3.f, 0.f, 3.f);
float_4 v = 0.f;
v += oscillator->sin() * simd::fmax(0.f, 1.f - simd::fabs(wave - 0.f));
v += oscillator->tri() * simd::fmax(0.f, 1.f - simd::fabs(wave - 1.f));
v += oscillator->saw() * simd::fmax(0.f, 1.f - simd::fabs(wave - 2.f));
v += oscillator->sqr() * simd::fmax(0.f, 1.f - simd::fabs(wave - 3.f));
outputs[OUT_OUTPUT].setVoltageSimd(5.f * v, c);
}
float_4 wave = simd::clamp(waveParam + inputs[WAVE_INPUT].getPolyVoltageSimd<float_4>(c) / 10.f * 3.f, 0.f, 3.f);
float_4 v = 0.f;
v += oscillator->sin() * simd::fmax(0.f, 1.f - simd::fabs(wave - 0.f));
v += oscillator->tri() * simd::fmax(0.f, 1.f - simd::fabs(wave - 1.f));
v += oscillator->saw() * simd::fmax(0.f, 1.f - simd::fabs(wave - 2.f));
v += oscillator->sqr() * simd::fmax(0.f, 1.f - simd::fabs(wave - 3.f));
outputs[OUT_OUTPUT].setVoltageSimd(5.f * v, c);
} }


outputs[OUT_OUTPUT].setChannels(channels); outputs[OUT_OUTPUT].setChannels(channels);


Loading…
Cancel
Save