#pragma once #include #include #include #include "Params.h" #include "Wavetable.h" #include "SynthVoice.h" #include "LFO.h" #include "FXProcessor.h" #include "ModulationMatrix.h" #include "MacroControls.h" namespace serum { // =========================================================================== // The synthesis engine: a fixed pool of voices, four global LFOs, a wavetable // library and the FX rack. Owns all per-block DSP and MIDI handling. // =========================================================================== class Engine { public: Engine(); void prepare (double sampleRate, int blockSize, juce::AudioProcessorValueTreeState& apvts); void reset(); // Ask for the DSP state to be cleared before the next block is rendered. // Safe to call from the message thread while controlLock is held: the audio // thread performs the reset in captureControls, so the DSP objects are only // ever touched by the audio thread. void requestReset() noexcept; void processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer& midi, juce::AudioProcessorValueTreeState& apvts, juce::AudioPlayHead* playhead); // MIDI void noteOn (int noteNumber, float velocity01); void noteOff (int noteNumber); void allNotesOff(); // Control-state accessors: hold getControlLock() while reading or editing. const juce::CriticalSection& getControlLock() const { return controlLock; } ModulationMatrix& getMatrix() { return matrix; } MacroControls& getMacros() { return macros; } const std::array& getLfos() const { return controlLfos; } const WavetableLibrary& getWavetables() const { return wavetables; } void setLfoShapeData (int index, const std::vector& data, int steps); private: std::array voices; std::array lfos, controlLfos; WavetableLibrary wavetables; FXProcessor fx; ModulationMatrix matrix, audioMatrix; MacroControls macros, audioMacros; juce::CriticalSection controlLock; bool resetRequested = false; // guarded by controlLock struct ParameterValue { std::atomic* source; float value; }; std::unordered_map parameterValues; double sr = 44100.0; int blockSize = 512; double bpm = 120.0; float pitchBend = 0.0f; float modWheel = 0.0f; juce::uint64 noteCounter = 0; juce::AudioBuffer mixBuffer; SynthVoice* findFreeVoice(); SynthVoice* stealVoice(); void captureControls(); float v (const char* id) const; int vic (const char* id, int maxValue) const; void readOscParams (const paramIds::Oscillator& ids, OscParams& out) const; }; } // namespace serum