#pragma once #include "core/Types.h" #include "dsp/FFTProcessor.h" #include "dsp/WindowFunctions.h" #include #include #include namespace baudline { class SpectrumAnalyzer { public: SpectrumAnalyzer(); void configure(const AnalyzerSettings& settings); const AnalyzerSettings& settings() const { return settings_; } void pushSamples(const float* data, size_t frames); bool hasNewSpectrum() const { return newSpectrumReady_; } // Number of physical spectra (1 for mono/IQ, numChannels for multi-ch). int numSpectra() const { return static_cast(channelSpectra_.size()); } // Per-channel dB magnitude spectrum. const std::vector& channelSpectrum(int ch) const { return channelSpectra_[ch]; } const std::vector& currentSpectrum() const { return channelSpectra_[0]; } const std::vector>& allSpectra() const { return channelSpectra_; } // Per-channel complex spectrum (for math ops like phase, cross-correlation). const std::vector>& channelComplex(int ch) const { return channelComplex_[ch]; } const std::vector>>& allComplex() const { return channelComplex_; } int spectrumSize() const { return fft_.spectrumSize(); } std::pair findPeak(int ch = 0) const; double binToFreq(int bin) const; void clearHistory(); const std::deque>& waterfallHistory(int ch = 0) const { return channelWaterfalls_[ch]; } private: void processBlock(); AnalyzerSettings settings_; FFTProcessor fft_; std::vector window_; float windowGain_ = 1.0f; std::vector accumBuf_; size_t accumPos_ = 0; size_t hopSize_ = 0; // Per-channel averaging std::vector> avgAccum_; int avgCount_ = 0; // Per-channel output: magnitude (dB) and complex std::vector> channelSpectra_; std::vector>> channelComplex_; std::vector>> channelWaterfalls_; bool newSpectrumReady_ = false; }; } // namespace baudline