diff --git a/lib/synth/CMakeLists.txt b/lib/synth/CMakeLists.txt deleted file mode 100644 index 4dc464f..0000000 --- a/lib/synth/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -cmake_minimum_required(VERSION 3.26) -project(synth) - -set(CMAKE_CXX_STANDARD 20) -if(MSVC) - set(CMAKE_CXX_FLAGS "/W4") - set(CMAKE_CXX_FLAGS_DEBUG "/DEBUG:FASTLINK /fp:fast") - set(CMAKE_CXX_FLAGS_RELEASE "/O2 /fp:fast /DNDEBUG") -else() - set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wdouble-promotion -Rpass-analysis=loop-vectorize") - set(CMAKE_CXX_FLAGS_DEBUG "-g -ffast-math") - set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -DNDEBUG") -endif() - -if(MSVC) - add_compile_definitions(_USE_MATH_DEFINES) -endif() - -add_library(synth - src/luts.cpp - src/synth.cpp - src/voicemanager.cpp - src/channel.cpp - src/preset.cpp - src/voice.cpp - src/dsp/oscillator.cpp - src/dsp/filter.cpp - src/dsp/adsr.cpp - src/dsp/reverb.cpp) -target_include_directories(synth PUBLIC include) \ No newline at end of file diff --git a/lib/synth/include/cc.h b/lib/synth/include/cc.h deleted file mode 100644 index fdff9d0..0000000 --- a/lib/synth/include/cc.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __CC_H__ -#define __CC_H__ - -#define CC_VOLUME 7 // Volume (Standard MIDI) -#define CC_FLT_ATK 16 // Filter Attack Time -#define CC_FLT_DEC 17 // Filter Decay Time -#define CC_FLT_SUS 18 // Filter Sustain -#define CC_FLT_REL 19 // Filter Release Time -#define CC_FLT_Q 71 // Timbre / Harmonic Content (Standard MIDI) -#define CC_AMP_REL 72 // Release Time (Standard MIDI) -#define CC_AMP_ATK 73 // Attack Time (Standard MIDI) -#define CC_FLT_FRQ 74 // Brightness (Standard MIDI) -#define CC_AMP_DEC 75 // Decay Time -#define CC_AMP_SUS 76 // Sustain -#define CC_OSC_DET 94 // Detune (Standard MIDI) -#define CC_MOD_FLT 20 // Mod Envelope Filter Gain -#define CC_KEY_TRK 21 // Filter Key Tracking -#define CC_OSC2PIT 22 // Oscillator 2 Pitch -#define CC_LFO_FRQ 23 // LFO Frequency -#define CC_LFO_PIT 24 // LFO Pitch Modulation -#define CC_LFO_FLT 25 // LFO Filter Modulation -#define CC_UNISON 26 // Unison Amount -#define CC_OSC_MIX 27 // Oscillator 1/2 Mix -#define CC_OSC1MDE 28 // Oscillator 1 Mode -#define CC_OSC2MDE 29 // Oscillator 2 Mode -#define CC_FLT_TYP 30 // Filter Type -#define CC_FLT_SLP 31 // Filter Slope -#define CC_RVB_SND 102 // Reverb Send -#define CC_NOI_MIX 103 // Noise Mix - -#endif \ No newline at end of file diff --git a/lib/synth/include/channel.h b/lib/synth/include/channel.h deleted file mode 100644 index 0918593..0000000 --- a/lib/synth/include/channel.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __PART_H__ -#define __PART_H__ - -#include -#include - -#include "globals.h" -#include "voicemanager.h" -#include "voice.h" -#include "preset.h" -#include "dsp/frame.h" -#include "luts.h" - -class Channel { -public: - VoiceManager::channel_t number; - VoiceManager* voiceManager; - Voice::Settings settings; - - Channel() : volume(1), pitchBend(0), modulation(0), lfoPhase(randFrac()) {} - - void loadPreset(const Preset* preset); - - void noteOn(int note, int vel); - void noteOff(int note); - void control(int cc, int val); - - bool tick(float *out, const size_t bufferSize) { - Voice** voices = voiceManager->getChannelVoices(number); - if(*voices == NULL) { - return false; - } - - const size_t numFrames = bufferSize / 2; - - float lfo[numFrames]; - for(size_t i = 0; i < numFrames; ++i) { - lfo[i] = fastSin(lfoPhase); - - lfoPhase += settings.lfoStep; - lfoPhase -= floorf(lfoPhase); - } - - float pitchMod[numFrames]; - for(size_t i = 0; i < numFrames; ++i) { - pitchMod[i] = settings.lfoPitchMod * lfo[i]; - } - - float fltMod[numFrames]; - for(size_t i = 0; i < numFrames; ++i) { - fltMod[i] = settings.lfoFltMod * lfo[i]; - } - - std::fill(out, out + bufferSize, 0.f); - for(Voice** voice = voices; *voice != NULL; ++voice) { - float voiceOut[bufferSize]; - (*voice)->tick(voiceOut, bufferSize, pitchMod, fltMod); - - for(size_t i = 0; i < bufferSize; ++i) { - out[i] += voiceOut[i]; - } - } - - return true; - } - -private: - float volume; - float pitchBend; - float modulation; - - float lfoPhase; -}; - -#endif \ No newline at end of file diff --git a/lib/synth/include/dsp/adsr.h b/lib/synth/include/dsp/adsr.h deleted file mode 100644 index 70740ec..0000000 --- a/lib/synth/include/dsp/adsr.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef __ADSR_H__ -#define __ADSR_H__ - -#include - -#include "../util.h" - -class ADSR { -public: - typedef struct { - float attackStep; - float decayStep; - float sustain; - float releaseStep; - } Envelope; - - Envelope const * env; - - ADSR() : state(IDLE), t(0), last(0) {}; - void reset(); - void assign(Envelope const * env); - void noteOn(); - void noteOff(); - bool isIdle() { - return state == IDLE; - } - - inline float tick() { - switch(state) { - case IDLE: - return 0; - - case ATTACK: - if(t < 1) { - t += env->attackStep; - last = t*t; - } else { - state = DECAY; - t = 1; - last = 1; - } - break; - - case DECAY: - if(t > 0) { - t -= env->decayStep; - //last = env->sustain + (1 - env->sustain) * curve(t); - last = env->sustain + (1 - env->sustain) * t*t; - } else { - state = SUSTAIN; - t = 1; - last = env->sustain; - } - break; - - case SUSTAIN: - last = env->sustain; - break; - - case RELEASE: - if(t > 0) { - t -= env->releaseStep; - return last * t*t; - } else { - state = IDLE; - t = 0; - last = 0; - } - break; - } - - return last; - } - -private: - enum { IDLE, ATTACK, DECAY, SUSTAIN, RELEASE } state; - float t; - float last; - - float curve(float gain) { - return 0.5f - 0.5f * cosf(clamp(gain * (float) M_PI, 0.f, M_PI)); - } -}; - -#endif \ No newline at end of file diff --git a/lib/synth/include/dsp/delayline.h b/lib/synth/include/dsp/delayline.h deleted file mode 100644 index f7a5544..0000000 --- a/lib/synth/include/dsp/delayline.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef __DELAYLINE_H__ -#define __DELAYLINE_H__ - -#include - -template -class DelayLine { -private: - float samples[CAPACITY] = {0}; - size_t cursor; - -public: - size_t size; - - DelayLine(size_t size = CAPACITY) : size(size) {} - - inline float get() { - while(cursor >= size) { - cursor -= size; - } - return samples[cursor]; - } - - inline float tick() { - ++cursor; - while(cursor >= size) { - cursor -= size; - } - return samples[cursor]; - } - - inline float tick(float in) { - while(cursor >= size) { - cursor -= size; - } - samples[cursor++] = in; - if(cursor == size) { - cursor = 0; - } - return samples[cursor]; - } - - inline void inject(float in, size_t pos) { - size_t index = cursor + pos; - while(index >= size) { - index -= size; - } - samples[index] = in; - } - - inline void inject(float* in, size_t num, size_t pos = 0) { - size_t index = cursor + pos; - while(index >= size) { - index -= size; - } - for(size_t i = 0; i < num; ++i) { - samples[index++] = *(in++); - if(index == size) { - index = 0; - } - } - } - - inline float tap(size_t n) { - size_t index = cursor + n; - if(index < size) { - return samples[index]; - } else { - return samples[index - size]; - } - } -}; - -#endif \ No newline at end of file diff --git a/lib/synth/include/dsp/filter.h b/lib/synth/include/dsp/filter.h deleted file mode 100644 index ea2f29b..0000000 --- a/lib/synth/include/dsp/filter.h +++ /dev/null @@ -1,233 +0,0 @@ -#ifndef __SVF_H__ -#define __SVF_H__ - -/* CEM3320/Oberheim/Phrophet-style filter as described here: https://arxiv.org/pdf/2111.05592.pdf */ - -#include -#include -#include -#include -#include - -#include "../globals.h" -#include "../util.h" -#include "../luts.h" - -#define FILTER_K_SCALE (2 * CV_FREQ_MIN / SAMPLE_RATE) - -inline float cvToK(float cv) { - return tanf((float) M_PI_2 * std::min(0.5f, (float) FILTER_K_SCALE * exp2f(cv))); -} - -class SVF12 { -protected: - float hp, bp, lp; - float as1, as2; - -public: - SVF12() : hp(0), bp(0), lp(0), as1(0), as2(0) {} - - inline void tick(float *in, float *hpo, float *bpo, float *lpo, size_t bufferSize, float *kK, float *kQ) { - float kQ_1[bufferSize]; - for(size_t i = 0; i < bufferSize; ++i) { - kQ_1[i] = 1.f / kQ[i]; - } - float kMul[bufferSize]; - for(size_t i = 0; i < bufferSize; ++i) { - kMul[i] = 1.f / (1.f + kK[i]*kQ_1[i] + kK[i]*kK[i]); - } - for(size_t i = 0; i < bufferSize; ++i) { - hp = (in[i] - (kQ_1[i] + kK[i]) * as1 - as2) * kMul[i]; - float au = hp * kK[i]; - bp = au + as1; - as1 = au + bp; - au = bp * kK[i]; - lp = au + as2; - as2 = au + lp; - - hpo && (hpo[i] = hp); - bpo && (bpo[i] = bp); - lpo && (lpo[i] = lp); - } - } -}; - -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: - 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; - SVF12 fltA, fltB; - float freq, res; - -public: - void assign(Settings const * settings); - - inline void tick(float *in, float *out, size_t bufferSize, float *freqMod) { - float dt = 1.f / (float) bufferSize; - - float kK[bufferSize]; - float dFreq = dt * (settings->freq - freq); - for(size_t i = 0; i < bufferSize; i++) { - kK[i] = fastCVtoK(freq + freqMod[i]); - freq += dFreq; - } - float kQ[bufferSize]; - float dRes = dt * (settings->res - res); - for(size_t i = 0; i < bufferSize; 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; - } - } -}; - -// 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/fm.h b/lib/synth/include/dsp/fm.h deleted file mode 100644 index 19ea385..0000000 --- a/lib/synth/include/dsp/fm.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef __FM_H__ -#define __FM_H__ - -#include - -#include "../util.h" - -class FM { -private: - float phase1 = randPhase(), phase2 = randPhase(), phase3 = randPhase(), phase4 = randPhase(), phase5 = randPhase(), phase6 = randPhase(); - float fb1 = 0.f, fb2 = 0.f; - -public: - struct Settings { - struct { - float pitch; - float level; - } ops[6]; - }; - Settings settings; - - float tick(float pitch, float fmEnv) { - float step3 = cvToStep(pitch); - float step2 = cvToStep(pitch + 3.807354922057604f); // Frequency Coarse = 14 - float step1 = cvToStep(pitch + 0.007195501404204f); // Detune = +7 - float step6 = cvToStep(pitch); - float step5 = cvToStep(pitch - 0.007231569231076f); // Detune = -7 - float step4 = cvToStep(pitch); - - float osc3 = fmEnv * 0.333f * sinf(phase3); - float osc2 = fmEnv * 0.333f * sinf(phase2 + (float) M_PI * osc3); - float osc1 = sinf(phase1 + (float) M_PI * osc2); - - float osc6 = fmEnv * 1.0f * sinf(phase6 + 0.0f * (float) M_PI * (fb1 + fb2)); - float osc5 = fmEnv * 1.0f * sinf(phase5 + (float) M_PI * osc6); - float osc4 = sinf(phase4 + (float) M_PI * osc5); - fb2 = fb1; - fb1 = osc4; - - phase1 += step1; - if(phase1 >= (float) PIx2) { - phase1 -= PIx2; - } - phase2 += step2; - if(phase2 >= (float) PIx2) { - phase2 -= PIx2; - } - phase3 += step3; - if(phase3 >= (float) PIx2) { - phase3 -= PIx2; - } - phase4 += step4; - if(phase4 >= (float) PIx2) { - phase4 -= PIx2; - } - phase5 += step5; - if(phase5 >= (float) PIx2) { - phase5 -= PIx2; - } - phase6 += step6; - if(phase6 >= (float) PIx2) { - phase6 -= PIx2; - } - - return osc1 + osc4; - } -}; - -/* -op6.detune 14 -op6.output_level 79 -op6.frequency_coarse 1 - -op5.detune 0 -op5.output_level 99 -op5.frequency_coarse 1 - -op4.detune 7 -op4.output_level 89 -op4.frequency_coarse 1 - -op3.detune 7 -op3.output_level 99 -op3.frequency_coarse 1 - -op2.detune 7 -op2.output_level 58 -op2.frequency_coarse 14 - -op1.detune 10 -op1.output_level 99 -op1.frequency_coarse 1 - -algorithm 4 -feedback 6 [0..7] - -RANGES - -opx.output_level [0, 99] -opX.frequency_coarse [0, 31] 0.50 - 31.00 X -op6.frequency_fine [0, 99] 1.00 - 1.99 X -opX.detune [0, 14] [-7, +7] -feedback [0, 7] - -*/ - -#endif \ No newline at end of file diff --git a/lib/synth/include/dsp/frame.h b/lib/synth/include/dsp/frame.h deleted file mode 100644 index 0259c2b..0000000 --- a/lib/synth/include/dsp/frame.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef __FRAME_H__ -#define __FRAME_H__ - -struct frame { - float l; - float r; - - inline frame operator+(const frame& rhs) { - return { - .l = l + rhs.l, - .r = r + rhs.r - }; - } - - inline frame operator+(float rhs) { - return { - .l = l + rhs, - .r = r + rhs - }; - } - - inline frame operator-(const frame& rhs) { - return { - .l = l - rhs.l, - .r = r - rhs.r - }; - } - - inline frame operator-(float rhs) { - return { - .l = l - rhs, - .r = r - rhs - }; - } - - inline frame operator*(const frame& rhs) { - return { - .l = l * rhs.l, - .r = r * rhs.r - }; - } - - inline frame operator*(float rhs) { - return { - .l = l * rhs, - .r = r * rhs - }; - } - - inline frame operator/(const frame& rhs) { - return { - .l = l / rhs.l, - .r = r / rhs.r - }; - } - - inline frame operator/(float rhs) { - return { - .l = l / rhs, - .r = r / rhs - }; - } - - inline frame operator+=(const frame& rhs) { - this->l += rhs.l; - this->r += rhs.r; - return *this; - } - - inline frame operator+=(float rhs) { - this->l += rhs; - this->r += rhs; - return *this; - } - - inline frame operator-=(const frame& rhs) { - this->l -= rhs.l; - this->r -= rhs.r; - return *this; - } - - inline frame operator-=(float rhs) { - this->l -= rhs; - this->r -= rhs; - return *this; - } - - inline frame operator*=(const frame& rhs) { - this->l *= rhs.l; - this->r *= rhs.r; - return *this; - } - - inline frame operator*=(float rhs) { - this->l *= rhs; - this->r *= rhs; - return *this; - } - - inline frame operator/=(const frame& rhs) { - this->l /= rhs.l; - this->r /= rhs.r; - return *this; - } - - inline frame operator/=(float rhs) { - this->l /= rhs; - this->r /= rhs; - return *this; - } -}; - -inline frame operator+(float lhs, const frame& rhs) { - return { - lhs + rhs.l, - lhs + rhs.r - }; -} - -inline frame operator-(float lhs, const frame& rhs) { - return { - lhs + rhs.l, - lhs + rhs.r - }; -} - -inline frame operator*(float lhs, const frame& rhs) { - return { - lhs * rhs.l, - lhs * rhs.r - }; -} - -inline frame operator/(float lhs, const frame& rhs) { - return { - lhs / rhs.l, - lhs / rhs.r - }; -} - -#endif \ No newline at end of file diff --git a/lib/synth/include/dsp/oscillator.h b/lib/synth/include/dsp/oscillator.h deleted file mode 100644 index 1b1f1e0..0000000 --- a/lib/synth/include/dsp/oscillator.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef __OSCILLATOR_H__ -#define __OSCILLATOR_H__ - -/* PolyBLEP oscillator inspired by: https://www.metafunction.co.uk/post/all-about-digital-oscillators-part-2-blits-bleps - * Further info about BLEP at: https://pbat.ch/sndkit/blep/ - */ - -#include -#include - -#include "../util.h" - -#include "../luts.h" - -class Oscillator { -public: - enum Mode { MODE_SINE = 0, MODE_SAW, MODE_SQUARE }; - - Mode const * mode; - float phase; // current waveform phase angle (radians) - float value; // current amplitude value - float driftAmount; - float driftValue; - - Oscillator() : phase(randFrac()), value(0), driftAmount(0.001f), driftValue(0) {} - - void assign(Mode const * mode); - - // Generate next output sample and advance the phase angle - inline void tick(float* out, size_t bufferSize, float *pitch, float* gain) { - size_t frameCount = bufferSize / 2; - - float driftBuf[frameCount]; - for(size_t i = 0; i < frameCount; ++i) { - driftValue += 0.005f * whiteNoise() - 0.00001f * driftValue; - driftBuf[i] = 1.0f + driftAmount * driftValue; - } - float phaseStepBuf[frameCount]; - for(size_t i = 0; i < frameCount; ++i) { - phaseStepBuf[i] = cvToStep(pitch[i]) * driftBuf[i]; - } - - float phaseBuf[frameCount]; - for(size_t i = 0; i < frameCount; ++i) { - phaseBuf[i] = phase; - phase += phaseStepBuf[i]; - phase -= floorf(phase); - } - - if(*mode == MODE_SINE) { - for(size_t i = 0, j = 0; i < frameCount; ++i) { - float value = fastSin(phaseBuf[i]); - out[j++] += gain[j & 1] * value; - out[j++] += gain[j & 1] * value; - } - } else if(*mode == MODE_SAW) { - for(size_t i = 0, j = 0; i < frameCount; ++i) { - float value = (2.0f * phaseBuf[i]) - 1.0f; // Render naive waveshape - value -= polyBlep(phaseBuf[i], phaseStepBuf[i]); // Layer output of Poly BLEP on top - out[j++] += gain[j & 1] * value; - out[j++] += gain[j & 1] * value; - } - } else if (*mode == MODE_SQUARE) { - for(size_t i = 0, j = 0; i < frameCount; ++i) { - float value = phaseBuf[i] < 0.5f ? 1.f : -1.f; // Render naive waveshape - - 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; - } - } - } - - inline float polyBlep(float t, float dt) { - // t-t^2/2 +1/2 - // 0 < t <= 1 - // discontinuities between 0 & 1 - if(t < dt) { - t /= dt; - return t + t - t * t - 1.0f; - } - - // t^2/2 +t +1/2 - // -1 <= t <= 0 - // discontinuities between -1 & 0 - else if(t > 1.0f - dt) { - t = (t - 1.0f) / dt; - return t * t + t + t + 1.0f; - } - - // no discontinuities - // 0 otherwise - else { - return 0.0; - } - } -}; - -#endif \ No newline at end of file diff --git a/lib/synth/include/dsp/phys.h b/lib/synth/include/dsp/phys.h deleted file mode 100644 index b30e2ea..0000000 --- a/lib/synth/include/dsp/phys.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __PHYS_H__ -#define __PHYS_H__ - -#include "../util.h" -#include "delayline.h" - -class Physical { -private: - DelayLine dl; - float lp = 0, lp2 = 0; - -public: - inline float tick(float pitch) { - int period = roundf(cvToPeriod(pitch)); - dl.size = period; - float out = dl.get(); - lp *= 0.99f; - lp += 0.90f * (out - lp); - dl.inject(lp, 0); - dl.tick(); - lp2 += 0.01f * (out - lp2); - return lp2; - } - - inline void pluck() { - float tmp[512]; - for(int i = 0; i < 512; ++i) { - tmp[i] = 8.f * (whiteNoise() + whiteNoise() + whiteNoise() + whiteNoise()); - } - dl.inject(tmp, 512); - } -}; - -#endif \ No newline at end of file diff --git a/lib/synth/include/dsp/reverb.h b/lib/synth/include/dsp/reverb.h deleted file mode 100644 index 372a284..0000000 --- a/lib/synth/include/dsp/reverb.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef __REVERB_H__ -#define __REVERB_H__ - -// Velvet noise reverb ("Late Reverberation Synthesis Using Filtered Velvet Noise") - -#include - -#include "globals.h" -#include "frame.h" -#include "stereodelayline.h" - -#define REVERB_FRAMES (3 * SAMPLE_RATE) -#define REVERB_TAPS 256 - -class Reverb { -private: - struct Tap { - size_t lp, rp; - float lg, rg; - }; - - StereoDelayLine dl; - Tap taps[REVERB_TAPS]; - float lpfL = 0.f, lpfR = 0.f; - float hpfL = 0.f, hpfR = 0.f; - -public: - Reverb(); - - frame tick(frame in) { - dl.tick(in); - - frame out{0, 0}; - - for(const Tap& tap : taps) { - out.l += tap.lg * dl.tap(tap.lp).l; - out.r += tap.rg * dl.tap(tap.rp).r; - } - - lpfL += 0.1f * (out.l - lpfL); - lpfR += 0.1f * (out.r - lpfR); - - hpfL += 0.05f * (lpfL - hpfL); - hpfR += 0.05f * (lpfR - hpfR); - - out.l = lpfL - hpfL; - out.r = lpfR - hpfR; - - return out; - } -}; - -#endif \ No newline at end of file diff --git a/lib/synth/include/dsp/stereodelayline.h b/lib/synth/include/dsp/stereodelayline.h deleted file mode 100644 index 9d255ff..0000000 --- a/lib/synth/include/dsp/stereodelayline.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __STEREODELAYLINE_H__ -#define __STEREODELAYLINE_H__ - -#include - -#include "frame.h" - -template -class StereoDelayLine { -private: - frame samples[CAPACITY] = {{0, 0}}; - size_t cursor; - -public: - size_t size; - - StereoDelayLine(size_t size = CAPACITY) : size(size) {} - - inline frame tick() { - ++cursor; - if(cursor == size) { - cursor = 0; - } - return samples[cursor]; - } - - inline frame tick(frame in) { - samples[cursor++] = in; - if(cursor == size) { - cursor = 0; - } - return samples[cursor]; - } - - inline frame tap(size_t n) { - size_t index = cursor + n; - if(index < size) { - return samples[index]; - } else { - return samples[index - size]; - } - } -}; - -#endif \ No newline at end of file diff --git a/lib/synth/include/dsp/stereosap.h b/lib/synth/include/dsp/stereosap.h deleted file mode 100644 index ba05e6f..0000000 --- a/lib/synth/include/dsp/stereosap.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __SAP_H__ -#define __SAP_H__ - -// Schroeder All-Pass (delay w/feedback) - -#include - -#include "stereodelayline.h" - -template -class StereoSAP { -private: - const size_t size; - StereoDelayLine dl; - -public: - float gain = 0.7; - - StereoSAP(size_t size = CAPACITY) : size(size) {} - - inline frame tick(frame in) { - frame fb = in + dl.tap(0) * gain; - frame out = dl.tick(fb) + fb * -gain; - return out; - } -}; - -#endif \ No newline at end of file diff --git a/lib/synth/include/globals.h b/lib/synth/include/globals.h deleted file mode 100644 index ff96702..0000000 --- a/lib/synth/include/globals.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __GLOBALS_H__ -#define __GLOBALS_H__ - -#define SAMPLE_RATE 96000 -#define SAMPLE_RATE_INV (1.0 / SAMPLE_RATE) - -#define FILTER_CV_MAX 9.25 // MIDI note "135" (19912.126958213178287 Hz) - -#endif \ No newline at end of file diff --git a/lib/synth/include/luts.h b/lib/synth/include/luts.h deleted file mode 100644 index 4720520..0000000 --- a/lib/synth/include/luts.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __LUTS_H__ -#define __LUTS_H__ - -#include - -#include "globals.h" -#include "util.h" - -#define SIN_LUT_SIZE 256 -#define K_LUT_SIZE 256 - -extern float sinLUT[SIN_LUT_SIZE]; -extern float kLUT[K_LUT_SIZE]; - -void genLUTs(); - -inline float fastSin(float t) { - t += randFrac() * (1.f / SIN_LUT_SIZE); - return sinLUT[(size_t) (t * SIN_LUT_SIZE) & (SIN_LUT_SIZE - 1)]; -} - -inline float fastCVtoK(float cv) { - return kLUT[std::min(K_LUT_SIZE - (size_t) 1, (size_t) (cv * (K_LUT_SIZE - 1) * (1.f / (float) FILTER_CV_MAX)))]; -} - -#endif \ No newline at end of file diff --git a/lib/synth/include/preset.h b/lib/synth/include/preset.h deleted file mode 100644 index d843621..0000000 --- a/lib/synth/include/preset.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef __PRESET_H__ -#define __PRESET_H__ - -#include "dsp/oscillator.h" -#include "dsp/filter.h" -#include "dsp/adsr.h" - -struct Preset { - typedef struct { - uint8_t attack; - uint8_t decay; - uint8_t sustain; - uint8_t release; - } Envelope; - - uint8_t unison; - - uint8_t osc1Mode; - uint8_t osc2Mode; - uint8_t oscMix; - uint8_t oscDetune; - uint8_t osc2Pitch; - - uint8_t noiseMix; - - struct { - uint8_t type; - uint8_t slope; - uint8_t freq; - uint8_t Q; - } filter; - - Envelope ampEnv; - Envelope modEnv; - - uint8_t modEnvFltGain; - uint8_t keyTrack; - uint8_t lfoFreq; - uint8_t lfoPitchMod; - uint8_t lfoFltMod; - - uint8_t reverb; -}; - -extern const Preset DEFAULT_PRESET; - -#endif \ No newline at end of file diff --git a/lib/synth/include/synth.h b/lib/synth/include/synth.h deleted file mode 100644 index e956cf8..0000000 --- a/lib/synth/include/synth.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __SYNTH_H__ -#define __SYNTH_H__ - -#include "voicemanager.h" -#include "channel.h" -#include "dsp/frame.h" -#include "dsp/reverb.h" -#include "luts.h" - -class Synth { -public: - Synth() { - genLUTs(); - - for(VoiceManager::channel_t i = 0; i < 16; ++i) { - channels[i].number = i; - channels[i].voiceManager = &voiceManager; - channels[i].loadPreset(&DEFAULT_PRESET); - } - } - - void noteOn(int ch, int note, int vel); - void noteOff(int ch, int note); - void control(int ch, int cc, int val); - - inline void tick(float* out, const size_t bufferSize) { - std::fill(out, out + bufferSize, 0.f); - - float reverbBus[bufferSize]; - std::fill(reverbBus, reverbBus + bufferSize, 0.f); - - for(auto& channel : channels) { - float chOut[bufferSize]; - if(!channel.tick(chOut, bufferSize)) { - continue; - } - - for(size_t i = 0; i < bufferSize; ++i) { - out[i] += chOut[i]; - } - - for(size_t i = 0; i < bufferSize; ++i) { - reverbBus[i] += channel.settings.reverb * chOut[i]; - } - } - - /* - 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; - } - } - -private: - VoiceManager voiceManager{}; - Channel channels[16]; - Reverb reverb; -}; - -#endif \ No newline at end of file diff --git a/lib/synth/include/util.h b/lib/synth/include/util.h deleted file mode 100644 index 9b83a4b..0000000 --- a/lib/synth/include/util.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef __UTIL_H__ -#define __UTIL_H__ - -#include -#include -#include - -#include "globals.h" - -#define unlikely(cond) __builtin_expect((cond), 0) -#define likely(cond) __builtin_expect((cond), 1) - -#define PIx2 (2 * M_PI) -#define PIx2_INV (1.0 / PIx2) - -#define CV_FREQ_MIN 32.703195662574829 // MIDI note 24 (C1) -#define MAX_SAMPLE_PERIOD ((int) (SAMPLE_RATE / CV_FREQ_MIN + 0.5)) - -inline float fakeSin(float x) { - x = 4.f * (x - 0.5f); - return x * (2.f - fabsf(x)); -} - -inline float clamp(float x, float a, float b) { - return fminf(b, fmaxf(a, x)); -} - -// Get timestamp in nanoseconds -inline uint64_t nanos() { - return std::chrono::duration_cast( - std::chrono::high_resolution_clock::now().time_since_epoch()) - .count(); -} - -inline float whiteNoise() { - static int32_t x1 = 0x70F4F854; - static int32_t x2 = 0xE1E9F0A7; - - x1 ^= x2; - float value = x2 * (2.0f / 0xFFFFFFFF); - x2 += x1; - - return value; -} - -inline float randFrac() { - static uint32_t x1 = 0x70F4F854; - static uint32_t x2 = 0xE1E9F0A7; - - x1 ^= x2; - float value = x2 * (1.f / 0x100000000); - x2 += x1; - - return value; -} - -inline float triangle(float phase) { - if(phase < 0.5f) { - return 2.f * phase - 1; - } else { - return 1 - 2.f * (phase - 0.5f); - } -} - -inline float cvToStep(float cv) { - return (float) CV_FREQ_MIN * exp2f(cv) * (float) SAMPLE_RATE_INV; -} - -inline float noteToCV(float note) { - return note / 12.f; -} - -inline float cvToPeriod(float cv) { - return (float) SAMPLE_RATE / ((float) CV_FREQ_MIN * exp2f(cv)); -} - -#endif \ No newline at end of file diff --git a/lib/synth/include/voice.h b/lib/synth/include/voice.h deleted file mode 100644 index 45f1377..0000000 --- a/lib/synth/include/voice.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef __VOICE_H__ -#define __VOICE_H__ - -#include "globals.h" -#include "preset.h" - -#include "dsp/oscillator.h" -#include "dsp/filter.h" -#include "dsp/adsr.h" - -#define MAX_OSCS 16 - -class Voice { -public: - typedef struct { - size_t unison; - - Oscillator::Mode osc1Mode; - Oscillator::Mode osc2Mode; - float oscMix; - float oscDetune; - float osc2Pitch; - - float noiseMix; - - FilterStereo::Settings filter; - - ADSR::Envelope ampEnv; - ADSR::Envelope modEnv; - - float modEnvFltGain; - float keyTrack; - float lfoStep; - float lfoPitchMod; - float lfoFltMod; - - float reverb; - } Settings; - -private: - Settings const * settings; - - ADSR adsrAmp; - ADSR adsrMod; - Oscillator osc[MAX_OSCS]; - FilterStereo filter; - -public: - int note; - float velocity; - float gain; - - void reset(); - void assign(Settings const * settings); - void noteOn(int note, float velocity = 1, float gain = 1.0f); - void noteOff(); - inline bool isIdle() { return adsrAmp.isIdle(); } - - inline void tick(float *out, const size_t bufferSize, float *pitchMod, float *fltMod) { - const size_t frameCount = bufferSize / 2; - - float basePitchBuf[frameCount]; - for(size_t i = 0; i < frameCount; ++i) { - basePitchBuf[i] = note + pitchMod[i]; - } - - 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) { - oscPitchBuf[i][j] = noteToCV(basePitchBuf[j] + detune + transpose); - } - detune += settings->oscDetune; - } - - float pan, panStep; - if(settings->unison > 1) { - pan = 0.f; - panStep = 1.f / (settings->unison - 1); - } else { - pan = 0.5f; - panStep = 0.f; - } - - float oscBuf[bufferSize]; - std::fill(oscBuf, oscBuf + bufferSize, 0.f); - for(size_t i = 0; i < settings->unison; ++i) { - float baseGain = (i & 1) ? settings->oscMix : (1 - settings->oscMix); - float gain[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, oscPitchBuf[i], gain); - } - - float noiseBuf[bufferSize]; - if(settings->unison > 1) { // Stereo noise - for(size_t i = 0; i < bufferSize; ++i) { - noiseBuf[i] = (1.f / 3.f) * (whiteNoise() + whiteNoise() + whiteNoise()); - } - } else { // Mono noise - for(size_t i = 0; i < bufferSize; ) { - float noise = (1.f / 3.f) * (whiteNoise() + whiteNoise() + whiteNoise()); - noiseBuf[i++] = noise; - noiseBuf[i++] = noise; - } - } - - for(size_t i = 0; i < bufferSize; ++i) { - oscBuf[i] += settings->noiseMix * (noiseBuf[i] - oscBuf[i]); - } - - const float keyTrackVal = settings->keyTrack * (note - 24) / 12.f; - - float fltModBuf[frameCount]; - 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(); - } - } -}; - -#endif \ No newline at end of file diff --git a/lib/synth/include/voicemanager.h b/lib/synth/include/voicemanager.h deleted file mode 100644 index bb2e6cd..0000000 --- a/lib/synth/include/voicemanager.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __VOICEMANAGER_H__ -#define __VOICEMANAGER_H__ - -#include - -#include "voice.h" - -#define NUM_VOICES 32 - -class VoiceManager { -public: - typedef unsigned int channel_t; - - VoiceManager(); - Voice* get(channel_t channel); - Voice** getChannelVoices(channel_t channel); - -private: - typedef unsigned int serial_t; - typedef unsigned int score_t; - - struct VoiceData { - channel_t channel; - serial_t serial; - Voice voice; - }; - - unsigned int serial; - VoiceData voices[NUM_VOICES]; - - unsigned int scoreVoice(VoiceData& voiceData); -}; - -#endif \ No newline at end of file diff --git a/lib/synth/src/channel.cpp b/lib/synth/src/channel.cpp deleted file mode 100644 index fb5f529..0000000 --- a/lib/synth/src/channel.cpp +++ /dev/null @@ -1,198 +0,0 @@ -#include - -#include "globals.h" -#include "cc.h" - -#include "channel.h" - -inline int midiToNote(int note) { - return note - 24; -} - -inline float timeToStep(float t) { - return (float) SAMPLE_RATE_INV / t; -} - -inline float ccToA(int x) { - return 5.0 * exp(9.2 * (x / 127.0) - 9.2); -} - -inline float ccToDR(int x) { - return 5.0 * exp(7.0 * (x / 127.0) - 7.0); -} - -inline float ccToLFOStep(int x) { - return (float) 0.1f * expf((1 + x) * 6.907755278982137f / 128.0f) * (float) SAMPLE_RATE_INV; -} - -inline float ccToLFOPitchMod(int x) { - return 6.f * x * x / 16129.f; -} - -inline float ccToLFOFltMod(int x) { - return (float) FILTER_CV_MAX * (x - 64) / 126.f; -} - -void Channel::loadPreset(const Preset * preset) { - settings.unison = 1 + floorf(preset->unison * 16.f / 128.f); - - settings.osc1Mode = Oscillator::Mode(preset->osc1Mode); - settings.osc2Mode = Oscillator::Mode(preset->osc2Mode); - settings.oscDetune = preset->oscDetune / 254.f; - settings.osc2Pitch = floorf(preset->osc2Pitch * 13.f / 128.f); - settings.oscMix = preset->oscMix / 127.f; - settings.noiseMix = preset->noiseMix / 127.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; - - settings.ampEnv.attackStep = timeToStep(ccToA(preset->ampEnv.attack)); - settings.ampEnv.decayStep = timeToStep(ccToDR(preset->ampEnv.decay)); - settings.ampEnv.sustain = preset->ampEnv.sustain / 127.f; - settings.ampEnv.releaseStep = timeToStep(ccToDR(preset->ampEnv.release)); - - settings.modEnv.attackStep = timeToStep(ccToA(preset->modEnv.attack)); - settings.modEnv.decayStep = timeToStep(ccToDR(preset->modEnv.decay)); - settings.modEnv.sustain = preset->modEnv.sustain / 127.f; - settings.modEnv.releaseStep = timeToStep(ccToDR(preset->modEnv.release)); - - settings.modEnvFltGain = (float) FILTER_CV_MAX * preset->modEnvFltGain / 127.f; - settings.keyTrack = preset->keyTrack / 127.f; - settings.lfoStep = ccToLFOStep(preset->lfoFreq); - settings.lfoPitchMod = ccToLFOPitchMod(preset->lfoPitchMod); - settings.lfoFltMod = ccToLFOFltMod(preset->lfoFltMod); - - settings.reverb = preset->reverb / 127.f; -} - -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); -} - -void Channel::noteOff(int note) { - Voice** voices = voiceManager->getChannelVoices(number); - for(Voice** voice = voices; *voice != NULL; ++voice) { - if((*voice)->note == midiToNote(note)) { - //printf("off: midi=%d note=%d\n", note, midiToNote(note)); - (*voice)->noteOff(); - } - } -} - -void Channel::control(int code, int value) { - switch(code) { - case CC_VOLUME: // Volume (Standard MIDI) - volume = value / 127.f; - break; - - case CC_FLT_ATK: // Filter Attack Time - settings.modEnv.attackStep = timeToStep(ccToA(value)); - break; - - case CC_FLT_DEC: // Filter Decay Time - settings.modEnv.decayStep = timeToStep(ccToDR(value)); - break; - - case CC_FLT_SUS: // Filter Sustain - settings.modEnv.sustain = value / 127.f; - break; - - case CC_FLT_REL: // Filter Release Time - settings.modEnv.releaseStep = timeToStep(ccToDR(value)); - break; - - case CC_FLT_Q: // Timbre / Harmonic Content (Standard MIDI) - settings.filter.res = value / 31.75f; - break; - - case CC_AMP_REL: // Release Time (Standard MIDI) - settings.ampEnv.releaseStep = timeToStep(ccToDR(value)); - break; - - case CC_AMP_ATK: // Attack Time (Standard MIDI) - settings.ampEnv.attackStep = timeToStep(ccToA(value)); - break; - - case CC_FLT_FRQ: // Brightness (Standard MIDI) - settings.filter.freq = (float) FILTER_CV_MAX * value / 127.f; - break; - - case CC_AMP_DEC: // Decay Time - settings.ampEnv.decayStep = timeToStep(ccToDR(value)); - break; - - case CC_AMP_SUS: // Sustain - settings.ampEnv.sustain = value / 127.f; - break; - - case CC_OSC_DET: // Detune (Standard MIDI) - settings.oscDetune = value / 254.f; - break; - - case CC_OSC2PIT: // Oscillator 2 Pitch - settings.osc2Pitch = floorf(value * (13.f / 128.f)); - break; - - case CC_MOD_FLT: // Mod Envelope Filter Gain - settings.modEnvFltGain = (float) FILTER_CV_MAX * value / 127.f; - break; - - case CC_KEY_TRK: // Filter Key Tracking - settings.keyTrack = value / 127.f; - break; - - case CC_LFO_FRQ: // LFO Frequency - settings.lfoStep = ccToLFOStep(value); - break; - - case CC_LFO_PIT: // LFO Pitch Modulation - settings.lfoPitchMod = ccToLFOPitchMod(value); - break; - - case CC_LFO_FLT: // LFO Filter Modulation - settings.lfoFltMod = ccToLFOFltMod(value); - break; - - case CC_UNISON: // Unison Amount - settings.unison = 1 + floorf(value * 16.f / 128.f); - break; - - case CC_OSC_MIX: // Oscillator 1/2 Mix - settings.oscMix = value / 127.f; - break; - - case CC_OSC1MDE: // Oscillator 1 Mode - settings.osc1Mode = Oscillator::Mode(floorf(3.f * value / 128.f)); - break; - - case CC_OSC2MDE: // Oscillator 2 Mode - settings.osc2Mode = Oscillator::Mode(floorf(3.f * value / 128.f)); - break; - - case CC_FLT_TYP: // Filter Type - settings.filter.type = FilterStereo::Type(floorf(3.f * value / 128.f)); - break; - - case CC_FLT_SLP: // Filter Slope - settings.filter.slope = FilterStereo::Slope(floorf(2.f * value / 128.f)); - break; - - case CC_RVB_SND: - settings.reverb = value / 127.f; - break; - - case CC_NOI_MIX: - settings.noiseMix = value / 127.f; - break; - - // LFO delay - // Reverb Time - // Reverb Brightness - // Reverb Density - } -} \ No newline at end of file diff --git a/lib/synth/src/dsp/adsr.cpp b/lib/synth/src/dsp/adsr.cpp deleted file mode 100644 index 38109a4..0000000 --- a/lib/synth/src/dsp/adsr.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "dsp/adsr.h" - -void ADSR::reset() { - state = IDLE; - t = 0; -} - -void ADSR::assign(Envelope const * env) { - this->env = env; -} - -void ADSR::noteOn() { - state = ATTACK; - t = 0; -} - -void ADSR::noteOff() { - if(state != RELEASE) { - state = RELEASE; - t = 1; - } -} \ No newline at end of file diff --git a/lib/synth/src/dsp/filter.cpp b/lib/synth/src/dsp/filter.cpp deleted file mode 100644 index e4fb0cf..0000000 --- a/lib/synth/src/dsp/filter.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "dsp/filter.h" - -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/dsp/oscillator.cpp b/lib/synth/src/dsp/oscillator.cpp deleted file mode 100644 index c58930c..0000000 --- a/lib/synth/src/dsp/oscillator.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "dsp/oscillator.h" - -void Oscillator::assign(Mode const * mode) { - this->mode = mode; -} \ No newline at end of file diff --git a/lib/synth/src/dsp/reverb.cpp b/lib/synth/src/dsp/reverb.cpp deleted file mode 100644 index a3de5ba..0000000 --- a/lib/synth/src/dsp/reverb.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include - -#include "dsp/reverb.h" - -Reverb::Reverb() { - size_t interval = REVERB_FRAMES / REVERB_TAPS - 4096 / REVERB_TAPS; - for(size_t tap = 0; tap < REVERB_TAPS; ++tap) { - float gain = exp2f(-8.f + 8.f * tap / (REVERB_TAPS - 1)); - taps[tap] = { - .lp = tap * interval + (rand() % interval), - .rp = tap * interval + (rand() % interval), - .lg = (rand() > RAND_MAX / 2 ? 1 : -1) * gain, - .rg = (rand() > RAND_MAX / 2 ? 1 : -1) * gain - }; - } -} diff --git a/lib/synth/src/luts.cpp b/lib/synth/src/luts.cpp deleted file mode 100644 index c43c962..0000000 --- a/lib/synth/src/luts.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include -//#include - -#include "luts.h" - -#include "dsp/filter.h" - -float sinLUT[SIN_LUT_SIZE]; -float kLUT[K_LUT_SIZE]; - -void genLUTs() { - for(size_t i = 0; i < SIN_LUT_SIZE; ++i) { - sinLUT[i] = sin((i * 2 * M_PI) / SIN_LUT_SIZE); - } - - for(size_t i = 0; i < K_LUT_SIZE; ++i) { - kLUT[i] = cvToK(i * FILTER_CV_MAX / (K_LUT_SIZE - 1)); - } -} \ No newline at end of file diff --git a/lib/synth/src/preset.cpp b/lib/synth/src/preset.cpp deleted file mode 100644 index c9059ba..0000000 --- a/lib/synth/src/preset.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "preset.h" - -const Preset DEFAULT_PRESET = { - .unison = 1, - - .osc1Mode = Oscillator::MODE_SAW, - .osc2Mode = Oscillator::MODE_SAW, - .oscMix = 64, - .oscDetune = 6, - .osc2Pitch = 0, - - .noiseMix = 0, - - .filter = { - .type = 0, - .slope = 22, - .freq = 32, - .Q = 25, - }, - - .ampEnv = { - .attack = 0, - .decay = 56, - .sustain = 64, - .release = 56 - }, - - .modEnv = { - .attack = 0, - .decay = 106, - .sustain = 0, - .release = 106 - }, - - .modEnvFltGain = 56, - .keyTrack = 127, - .lfoFreq = 64, - .lfoPitchMod = 0, - .lfoFltMod = 64, - - .reverb = 16 -}; \ No newline at end of file diff --git a/lib/synth/src/synth.cpp b/lib/synth/src/synth.cpp deleted file mode 100644 index 33972eb..0000000 --- a/lib/synth/src/synth.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include - -#include "synth.h" - -void Synth::noteOn(int ch, int note, int vel) { - printf("Note On: ch=%d note=%d vel=%d\n", ch, note, vel); - channels[ch].noteOn(note, vel); -} - -void Synth::noteOff(int ch, int note) { - printf("Note Off: ch=%d note=%d\n", ch, note); - channels[ch].noteOff(note); -} - -void Synth::control(int ch, int cc, int val) { - printf("Controller: ch=%d cc=%d val=%d\n", ch, cc, val); - channels[ch].control(cc, val); -} \ No newline at end of file diff --git a/lib/synth/src/voice.cpp b/lib/synth/src/voice.cpp deleted file mode 100644 index 94100d0..0000000 --- a/lib/synth/src/voice.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "voice.h" - -void Voice::reset() { - adsrAmp.reset(); - adsrMod.reset(); -} - -void Voice::assign(Settings const * settings) { - this->settings = settings; - adsrAmp.assign(&settings->ampEnv); - adsrMod.assign(&settings->modEnv); - for(size_t i = 0; i < MAX_OSCS; ++i) { - if(i & 1) { - osc[i].assign(&settings->osc2Mode); - } else { - osc[i].assign(&settings->osc1Mode); - } - } - filter.assign(&settings->filter); -} - -void Voice::noteOn(int note, float velocity, float gain) { - this->note = note; - this->velocity = velocity; - this->gain = gain; - adsrAmp.noteOn(); - adsrMod.noteOn(); -} - -void Voice::noteOff() { - adsrAmp.noteOff(); - adsrMod.noteOff(); -} \ No newline at end of file diff --git a/lib/synth/src/voicemanager.cpp b/lib/synth/src/voicemanager.cpp deleted file mode 100644 index 1f26bc0..0000000 --- a/lib/synth/src/voicemanager.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include - -#include "voicemanager.h" - -#define VOICE_SCORE_MSB (8 * sizeof(score_t) - 1) - -#define VOICE_SCORE_ACTIVE ( 1 << (VOICE_SCORE_MSB - 0)) -#define VOICE_SCORE_CHANNEL(channel) ((score_t) (channel) << (VOICE_SCORE_MSB - 4)) -#define VOICE_SCORE_SERIAL(serial) ((score_t) serial & ((1 << (VOICE_SCORE_MSB - 4)) - 1)) - -VoiceManager::VoiceManager() : serial(0) { - for(VoiceData& vd : voices) { - vd.channel = 0; - vd.serial = 0; - } -} - -VoiceManager::score_t VoiceManager::scoreVoice(VoiceData& voiceData) { - return - (voiceData.voice.isIdle() ? 0 : VOICE_SCORE_ACTIVE) | - VOICE_SCORE_CHANNEL(voiceData.channel) | - VOICE_SCORE_SERIAL(voiceData.serial); -} - -Voice * VoiceManager::get(channel_t channel) { - // Sort idle voices first, then by highest channel and lowest serial - std::sort(std::begin(voices), std::end(voices), [this](VoiceData& a, VoiceData& b) { - return scoreVoice(a) < scoreVoice(b); - }); - -/* - putchar('\n'); - for(VoiceData& vd : voices) { - printf("channel=%d serial=%d idle=%d note=%d score=%x\n", vd.channel, vd.serial, vd.voice.isIdle(), vd.voice.note, scoreVoice(vd)); - } - putchar('\n'); -*/ - - VoiceData& voiceData = voices[0]; - if(!voiceData.voice.isIdle()) { - printf("Out of voices\n"); - } - voiceData.channel = channel; - voiceData.serial = serial++; - voiceData.voice.reset(); - - return &voiceData.voice; -} - -Voice** VoiceManager::getChannelVoices(channel_t channel) { - static Voice* result[NUM_VOICES + 1]; - Voice** voice = result; - bool empty = true; - for(VoiceData& voiceData : voices) { - if(!voiceData.voice.isIdle()) { - empty = false; - if(voiceData.channel == channel) { - *voice++ = &voiceData.voice; - } - } - } - *voice = NULL; - - // Reset serial if voice table is empty - if(empty) { - serial = 0; - } - - return result; -}