#pragma once #include #include "EQBand.h" class FIREngine : private juce::Thread { public: static constexpr int defaultFFTOrder = 13; // 8192 taps static constexpr int maxBands = 8; FIREngine(); ~FIREngine() override; void start (double sampleRate); void stop(); // Called from GUI thread void setBands (const std::vector& newBands); void setFFTOrder (int order); // Called from audio thread — returns new FIR if available, nullptr otherwise std::unique_ptr> getNewFIR(); // Get magnitude response in dB for display (thread-safe copy) std::vector getMagnitudeResponseDb() const; int getFIRLength() const { return 1 << fftOrder.load(); } int getLatencySamples() const { return getFIRLength() / 2; } private: void run() override; juce::AudioBuffer generateFIR (const std::vector& bands, double sr, int order); std::atomic sampleRate { 44100.0 }; std::atomic fftOrder { defaultFFTOrder }; std::atomic needsUpdate { true }; std::vector currentBands; mutable juce::SpinLock bandLock; std::unique_ptr> pendingFIR; juce::SpinLock firLock; std::vector magnitudeDb; mutable juce::SpinLock magLock; };