#pragma once #include #include "Params.h" #include "Wavetable.h" #include "Oscillator.h" #include "SubOscillator.h" #include "NoiseOscillator.h" #include "FilterBank.h" #include "Envelope.h" #include "ModulationMatrix.h" #include "MacroControls.h" namespace serum { // =========================================================================== // Everything a voice needs to render one block. Global (non per-voice) values // are provided by the engine; the voice adds its own per-voice modulation. // =========================================================================== struct RenderContext { double sampleRate = 44100.0; const WavetableLibrary* wavetables = nullptr; float lfoValues[kNumLfos] { 0.0f, 0.0f, 0.0f, 0.0f }; float macroValues[kNumMacros] { 0.0f, 0.0f, 0.0f, 0.0f }; float modWheel = 0.0f; float pitchBend = 0.0f; float pitchBendRange = 2.0f; const ModulationMatrix* matrix = nullptr; const MacroControls* macros = nullptr; OscParams oscA; OscParams oscB; bool subOn = false; int subShape = 0; int subOct = -1; float subLevel = 0.0f; bool noiseOn = false; int noiseType = 0; float noiseLevel = 0.0f; FilterBankParams filters; float envAttack[4] { 0.01f, 0.01f, 0.01f, 0.01f }; float envDecay[4] { 0.2f, 0.2f, 0.2f, 0.2f }; float envSustain[4]{ 0.7f, 0.7f, 0.7f, 0.7f }; float envRelease[4]{ 0.3f, 0.3f, 0.3f, 0.3f }; float envCurve[4] { 0.5f, 0.5f, 0.5f, 0.5f }; }; // =========================================================================== // One synthesis voice: two oscillators + sub + noise -> filter bank -> amp // envelope. Four envelopes provide per-voice modulation sources. // =========================================================================== class SynthVoice { public: void prepare (double sampleRate, int maxBlockSize); void reset(); void noteOn (int noteNumber, float velocity, double freqHz, juce::uint32 seed); void noteOff(); void render (float* outL, float* outR, int numSamples, const RenderContext& ctx) noexcept; bool isActive() const noexcept { return active; } bool isReleased() const noexcept { return released; } int getNote() const noexcept { return note; } juce::uint64 getNoteId() const noexcept { return noteId; } private: Oscillator oscA, oscB; SubOscillator sub; NoiseOscillator noise; FilterBank filters; std::array env; int note = -1; float velocity = 0.0f; double baseFreq = 0.0; bool active = false; bool released = false; juce::uint64 noteId = 0; bool oscillatorsNeedNoteOn = false; juce::uint32 seed = 0; float noteRandom = 0.5f; juce::AudioBuffer scratch; // 2 channels }; } // namespace serum