diff --git a/lib/synth/include/channel.h b/lib/synth/include/channel.h index 44fe43c..0918593 100644 --- a/lib/synth/include/channel.h +++ b/lib/synth/include/channel.h @@ -53,8 +53,8 @@ public: std::fill(out, out + bufferSize, 0.f); for(Voice** voice = voices; *voice != NULL; ++voice) { - float voiceOut[numFrames]; - (*voice)->tick(voiceOut, numFrames, pitchMod, fltMod); + float voiceOut[bufferSize]; + (*voice)->tick(voiceOut, bufferSize, pitchMod, fltMod); for(size_t i = 0; i < bufferSize; ++i) { out[i] += voiceOut[i]; diff --git a/lib/synth/include/dsp/filter.h b/lib/synth/include/dsp/filter.h index 714e7c5..ea2f29b 100644 --- a/lib/synth/include/dsp/filter.h +++ b/lib/synth/include/dsp/filter.h @@ -52,6 +52,46 @@ public: } }; +class SVF12Stereo { +protected: + float hp[2], bp[2], lp[2]; + float as1[2], as2[2]; + +public: + SVF12Stereo() : hp{0, 0}, bp{0, 0}, lp{0, 0}, as1{0, 0}, as2{0, 0} {} + + inline void tick(float *in, float *hpo, float *bpo, float *lpo, size_t bufferSize, float *kK, float *kQ) { + size_t frameCount = bufferSize / 2; + + float kQ_1[frameCount]; + for(size_t i = 0; i < frameCount; ++i) { + kQ_1[i] = 1.f / kQ[i]; + } + float kMul[frameCount]; + for(size_t i = 0; i < frameCount; ++i) { + kMul[i] = 1.f / (1.f + kK[i]*kQ_1[i] + kK[i]*kK[i]); + } + for(size_t i = 0, j = 0; i < bufferSize; ++i) { + size_t ch = i & 1; + + hp[ch] = (in[i] - (kQ_1[j] + kK[j]) * as1[ch] - as2[ch]) * kMul[j]; + float au = hp[ch] * kK[j]; + bp[ch] = au + as1[ch]; + as1[ch] = au + bp[ch]; + au = bp[ch] * kK[j]; + lp[ch] = au + as2[ch]; + as2[ch] = au + lp[ch]; + + hpo && (hpo[i] = hp[ch]); + bpo && (bpo[i] = bp[ch]); + lpo && (lpo[i] = lp[ch]); + + j += ch; + } + } +}; + + // 12 and 24 dB/oct class Filter { public: @@ -120,5 +160,74 @@ public: } }; +// 12 and 24 dB/oct +class FilterStereo { +public: + enum Type { + TYPE_LP = 0, + TYPE_BP, + TYPE_HP + }; + + enum Slope { + SLOPE_12 = 0, + SLOPE_24, + }; + + typedef struct { + float freq; + float res; + Type type; + Slope slope; + } Settings; + +private: + Settings const * settings; + SVF12Stereo fltA, fltB; + float freq, res; + +public: + void assign(Settings const * settings); + + inline void tick(float *in, float *out, size_t bufferSize, float *freqMod) { + size_t frameCount = bufferSize / 2; + + float dt = 1.f / (float) frameCount; + + float kK[frameCount]; + float dFreq = dt * (settings->freq - freq); + for(size_t i = 0; i < frameCount; i++) { + kK[i] = fastCVtoK(freq + freqMod[i]); + freq += dFreq; + } + float kQ[frameCount]; + float dRes = dt * (settings->res - res); + for(size_t i = 0; i < frameCount; i++) { + kQ[i] = (float) M_SQRT1_2 + res; + res += dRes; + } + + switch(settings->type) { + case TYPE_LP: + fltA.tick(in, NULL, NULL, out, bufferSize, kK, kQ); + if(settings->slope == SLOPE_24) { + fltB.tick(out, NULL, NULL, out, bufferSize, kK, kQ); + } + break; + case TYPE_BP: + fltA.tick(in, NULL, out, NULL, bufferSize, kK, kQ); + if(settings->slope == SLOPE_24) { + fltB.tick(out, NULL, out, NULL, bufferSize, kK, kQ); + } + break; + case TYPE_HP: + fltA.tick(in, out, NULL, NULL, bufferSize, kK, kQ); + if(settings->slope == SLOPE_24) { + fltB.tick(out, out, NULL, NULL, bufferSize, kK, kQ); + } + break; + } + } +}; #endif \ No newline at end of file diff --git a/lib/synth/include/dsp/oscillator.h b/lib/synth/include/dsp/oscillator.h index 99b7a58..1b1f1e0 100644 --- a/lib/synth/include/dsp/oscillator.h +++ b/lib/synth/include/dsp/oscillator.h @@ -67,8 +67,8 @@ public: value += polyBlep(phaseBuf[i], phaseStepBuf[i]); // Layer output of Poly BLEP on top (flip) value -= polyBlep(fmodf(phaseBuf[i] + 0.5f, 1.0f), phaseStepBuf[i]); // Layer output of Poly BLEP on top (flop) - out[j++] = gain[j & 1] * value; - out[j++] = gain[j & 1] * value; + out[j++] += gain[j & 1] * value; + out[j++] += gain[j & 1] * value; } } } diff --git a/lib/synth/include/synth.h b/lib/synth/include/synth.h index d2746e5..e956cf8 100644 --- a/lib/synth/include/synth.h +++ b/lib/synth/include/synth.h @@ -44,12 +44,14 @@ public: } } + /* for(size_t i = 0; i < bufferSize; i += 2) { frame f = {reverbBus[i], reverbBus[i + 1]}; f = reverb.tick(f); out[i] += f.l; out[i + 1] += f.r; } + */ for(size_t i = 0; i < bufferSize; ++i) { out[i] *= 0.125f; diff --git a/lib/synth/include/voice.h b/lib/synth/include/voice.h index 9ad311f..45f1377 100644 --- a/lib/synth/include/voice.h +++ b/lib/synth/include/voice.h @@ -8,7 +8,7 @@ #include "dsp/filter.h" #include "dsp/adsr.h" -#define MAX_OSCS 8 +#define MAX_OSCS 16 class Voice { public: @@ -23,7 +23,7 @@ public: float noiseMix; - Filter::Settings filter; + FilterStereo::Settings filter; ADSR::Envelope ampEnv; ADSR::Envelope modEnv; @@ -43,7 +43,7 @@ private: ADSR adsrAmp; ADSR adsrMod; Oscillator osc[MAX_OSCS]; - Filter filter; + FilterStereo filter; public: int note; @@ -64,12 +64,12 @@ public: basePitchBuf[i] = note + pitchMod[i]; } - float oscCVBuf[MAX_OSCS][frameCount]; + float oscPitchBuf[MAX_OSCS][frameCount]; float detune = -settings->oscDetune * 0.5f * (settings->unison - 1); for(size_t i = 0; i < settings->unison; ++i) { float transpose = (i & 1) ? settings->osc2Pitch : 0; for(size_t j = 0; j < frameCount; ++j) { - oscCVBuf[i][j] = noteToCV(basePitchBuf[i] + detune + transpose); + oscPitchBuf[i][j] = noteToCV(basePitchBuf[j] + detune + transpose); } detune += settings->oscDetune; } @@ -88,10 +88,10 @@ public: for(size_t i = 0; i < settings->unison; ++i) { float baseGain = (i & 1) ? settings->oscMix : (1 - settings->oscMix); float gain[2]; - gain[0] = sinf((1.f - pan) * (float) M_PI_2); - gain[1] = sinf(pan * (float) M_PI_2); + gain[0] = baseGain * sinf((1.f - pan) * (float) M_PI_2); + gain[1] = baseGain * sinf(pan * (float) M_PI_2); pan += panStep; - osc[i].tick(oscBuf, bufferSize, oscCVBuf[i], gain); + osc[i].tick(oscBuf, bufferSize, oscPitchBuf[i], gain); } float noiseBuf[bufferSize]; @@ -117,6 +117,8 @@ public: for(size_t i = 0; i < frameCount; ++i) { fltModBuf[i] = settings->modEnvFltGain * adsrMod.tick() + keyTrackVal + fltMod[i]; } + + //std::copy(oscBuf, oscBuf + bufferSize, out); filter.tick(oscBuf, out, bufferSize, fltModBuf); for(size_t i = 0; i < bufferSize; ++i) { out[i] *= gain * adsrAmp.tick(); diff --git a/lib/synth/src/channel.cpp b/lib/synth/src/channel.cpp index dced626..fb5f529 100644 --- a/lib/synth/src/channel.cpp +++ b/lib/synth/src/channel.cpp @@ -34,7 +34,7 @@ inline float ccToLFOFltMod(int x) { } void Channel::loadPreset(const Preset * preset) { - settings.unison = 1 + floorf(preset->unison * 8.f / 128.f); + settings.unison = 1 + floorf(preset->unison * 16.f / 128.f); settings.osc1Mode = Oscillator::Mode(preset->osc1Mode); settings.osc2Mode = Oscillator::Mode(preset->osc2Mode); @@ -43,8 +43,8 @@ void Channel::loadPreset(const Preset * preset) { settings.oscMix = preset->oscMix / 127.f; settings.noiseMix = preset->noiseMix / 127.f; - settings.filter.type = Filter::Type(floorf(3.f * preset->filter.type / 128.f)); - settings.filter.slope = Filter::Slope(floorf(2.f * preset->filter.slope / 128.f)); + settings.filter.type = FilterStereo::Type(floorf(3.f * preset->filter.type / 128.f)); + settings.filter.slope = FilterStereo::Slope(floorf(2.f * preset->filter.slope / 128.f)); settings.filter.freq = (float) FILTER_CV_MAX * preset->filter.freq / 127.f; settings.filter.res = preset->filter.Q / 31.75f; @@ -71,7 +71,7 @@ void Channel::noteOn(int note, int velocity) { //printf("on: midi=%d note=%d\n", note, midiToNote(note)); Voice* const voice = voiceManager->get(number); voice->assign(&settings); - voice->noteOn(midiToNote(note), velocity / 127.f, 1.f, 0.5f); + voice->noteOn(midiToNote(note), velocity / 127.f, 1.f); } void Channel::noteOff(int note) { @@ -159,7 +159,7 @@ void Channel::control(int code, int value) { break; case CC_UNISON: // Unison Amount - settings.unison = 1 + floorf(value * 8.f / 128.f); + settings.unison = 1 + floorf(value * 16.f / 128.f); break; case CC_OSC_MIX: // Oscillator 1/2 Mix @@ -175,11 +175,11 @@ void Channel::control(int code, int value) { break; case CC_FLT_TYP: // Filter Type - settings.filter.type = Filter::Type(floorf(3.f * value / 128.f)); + settings.filter.type = FilterStereo::Type(floorf(3.f * value / 128.f)); break; case CC_FLT_SLP: // Filter Slope - settings.filter.slope = Filter::Slope(floorf(2.f * value / 128.f)); + settings.filter.slope = FilterStereo::Slope(floorf(2.f * value / 128.f)); break; case CC_RVB_SND: diff --git a/lib/synth/src/dsp/filter.cpp b/lib/synth/src/dsp/filter.cpp index b983d74..e4fb0cf 100644 --- a/lib/synth/src/dsp/filter.cpp +++ b/lib/synth/src/dsp/filter.cpp @@ -4,4 +4,10 @@ void Filter::assign(Settings const * settings) { this->settings = settings; freq = settings->freq; res = settings->res; +} + +void FilterStereo::assign(Settings const * settings) { + this->settings = settings; + freq = settings->freq; + res = settings->res; } \ No newline at end of file diff --git a/lib/synth/src/voice.cpp b/lib/synth/src/voice.cpp index 23b70ed..94100d0 100644 --- a/lib/synth/src/voice.cpp +++ b/lib/synth/src/voice.cpp @@ -19,11 +19,10 @@ void Voice::assign(Settings const * settings) { filter.assign(&settings->filter); } -void Voice::noteOn(int note, float velocity, float gain, float pan) { +void Voice::noteOn(int note, float velocity, float gain) { this->note = note; this->velocity = velocity; this->gain = gain; - this->pan = pan; adsrAmp.noteOn(); adsrMod.noteOn(); }