#pragma once #include #include "Params.h" struct VParams { float osc1w = 2, osc2w = 3, detune = 8, oscMix = 52.f; float fltType = 1, fltCut = 3400.f, fltRes = 0.18f, fltEnv = 52.f, fltKey = 40.f; float ampA = 0.008f, ampD = 0.26f, ampS = 0.70f, ampR = 0.35f; float fA = 0.02f, fD = 0.16f, fS = 0.26f, fR = 0.25f; float lfoRate = 4.2f, lfoShape = 0, lfoDepth = 0.22f, lfoTarget = 0; float fxType = 1, fxAmt = 0.30f, fxTime = 0.28f; float vol = 0.85f, pan = 0.0f, poly = 10.f, glide = 0.f, tune = 0.f; float hq = 0.0f; float arpOn = 0, arpRate = 2, arpPattern = 0, arpOct = 1, arpGate = 70; void update (const juce::AudioProcessorValueTreeState& apvts) { auto get = [&] (const char* id) { return apvts.getRawParameterValue (id) -> load(); }; osc1w = get ("osc1wave"); osc2w = get ("osc2wave"); detune = get ("detune"); oscMix = get ("oscmix"); fltType = get ("flttype"); fltCut = get ("fltcut"); fltRes = get ("fltres"); fltEnv = get ("fltenv"); fltKey = get ("fltkey"); ampA = get ("ampA"); ampD = get ("ampD"); ampS = get ("ampS"); ampR = get ("ampR"); fA = get ("fenvA"); fD = get ("fenvD"); fS = get ("fenvS"); fR = get ("fenvR"); lfoRate = get ("lforate"); lfoShape = get ("lfoshape"); lfoDepth = get ("lfodepth"); lfoTarget= get ("lfotarget"); fxType = get ("fxtype"); fxAmt = get ("fxamt"); fxTime = get ("fxtime"); vol = get ("vol"); pan = get ("pan"); poly = get ("poly"); glide = get ("glide"); tune = get ("tune"); hq = get ("hq"); arpOn = get ("arpon"); arpRate = get ("arprate"); arpPattern = get ("arppattern"); arpOct = get ("arpoct"); arpGate = get ("arpgate"); } }; // --------------------------------------------------------------------------- class Env { public: enum State { Off, Atk, Dec, Sus, Rel }; void setRates (float a, float d, float s, float r, double sr) { srInv = 1.0 / sr; attTau = 1.0f / (0.001f + 0.25f * a); decTau = 1.0f / (0.001f + 0.35f * d); relTau = 1.0f / (0.001f + 0.30f * r); susL = s; } void noteOn () { st = Atk; } void noteOff () { if (st != Off && st != Rel) st = Rel; } void reset (float v = 0.0f) { cur = v; st = Off; } float next() { switch (st) { case Atk: cur += (1.0f - cur) * std::min (1.0f, (float) (attTau * srInv) * 8.0f); if (cur >= 1.0f) { cur = 1.0f; st = Dec; } break; case Dec: cur = susL + (cur - susL) * std::exp (-decTau * (float) srInv); if (std::abs (cur - susL) < 0.001f) { cur = susL; st = Sus; } break; case Sus: break; case Rel: cur *= std::exp (-relTau * (float) srInv); if (cur < 0.0002f) { cur = 0.0f; st = Off; } break; case Off: break; } return cur; } bool running() const { return st != Off; } float getCur() const { return cur; } State getState() const { return st; } private: float cur = 0.0f, susL = 0.7f; float attTau = 1.0f, decTau = 1.0f, relTau = 1.0f; double srInv = 1.0 / 48000.0; State st = Off; }; // --------------------------------------------------------------------------- class SynthEngine { public: SynthEngine(); ~SynthEngine(); void setSampleRate (double sr); void noteOn (int midiNote, float velocity); void noteOff (int midiNote); void allNotesOff (bool immediate); void sustainPedal (bool down); void pitchBend (float cents); void modWheel (float v); void render (const VParams& p, float* left, float* right, int numSamples); int activeVoices() const noexcept { return active; } private: struct Voice { bool active = false; int note = 0; float vel = 1.0f; float panL = 0.71f, panR = 0.71f; float curFreq = 0.0f, targetFreq = 0.0f; double ph1 = 0.0, ph2 = 0.0, lfoPh = 0.0; float lfoSH = 0.0f; int lfoIdx = 0; Env amp, flt; float lp = 0.0f, bp = 0.0f, f1c = 0.0f; float fcSm = 0.0f; float outSmooth = 0.0f; }; static constexpr int maxVoice = 16; Voice voices[maxVoice]; double sr = 48000.0; int active = 0; int polyLimit = 16; float mod = 0.0f, bendCents = 0.0f, bendSmooth = 0.0f; bool pedal = false; float lastNoteFreq = 440.0f, lastGlide = 0.0f, lastPan = 0.0f; int stealIdx = 0; juce::Random rng; juce::Array sustainedNotes; float osc (int wave, double ph); Voice* acquireVoice(); };