#pragma once #include #include #include #include struct StereoSample { float mid = 0.0f; float side = 0.0f; float age = 0.0f; }; struct StereoMetrics { float correlation = 0.0f; // -1 to +1 float stereoWidth = 0.0f; // dB float midLevel = 0.0f; // dB float sideLevel = 0.0f; // dB float balance = 0.0f; // dB (L-R) float phaseAngle = 0.0f; // degrees float crestFactor = 0.0f; // dB float peakL = 0.0f; // dB float peakR = 0.0f; // dB float rmsL = 0.0f; // dB float rmsR = 0.0f; // dB }; class TerionProcessor final : public juce::AudioProcessor { public: static constexpr int kMaxPoints = 8192; TerionProcessor(); ~TerionProcessor() override; void prepareToPlay(double sampleRate, int samplesPerBlock) override; void releaseResources() override; void processBlock(juce::AudioBuffer&, juce::MidiBuffer&) override; juce::AudioProcessorEditor* createEditor() override; bool hasEditor() const override { return true; } const juce::String getName() const override { return "Terion"; } bool acceptsMidi() const override { return false; } bool producesMidi() const override { return false; } bool isMidiEffect() const override { return false; } double getTailLengthSeconds() const override { return 0.0; } int getNumPrograms() override { return 1; } int getCurrentProgram() override { return 0; } void setCurrentProgram(int) override {} const juce::String getProgramName(int) override { return {}; } void changeProgramName(int, const juce::String&) override {} void getStateInformation(juce::MemoryBlock& destData) override; void setStateInformation(const void* data, int sizeInBytes) override; const std::vector& getPoints() const { return points; } const StereoMetrics& getMetrics() const { return metrics; } juce::AudioProcessorValueTreeState apvts; enum class ParameterID { fadeTime = 1, sensitivity = 2, dotSize = 3, smoothing = 4, freeze = 5 }; private: std::vector points; StereoMetrics metrics; int writePos = 0; bool filled = false; // Smoothing filters float midSmoothed = 0.0f; float sideSmoothed = 0.0f; // Metrics calculation state float sumMid = 0.0f; float sumSide = 0.0f; float sumMidSide = 0.0f; float sumMid2 = 0.0f; float sumSide2 = 0.0f; float peakMid = 0.0f; float peakSide = 0.0f; int metricsCount = 0; void addPoint(float mid, float side, float age); void updateMetrics(float mid, float side, float left, float right); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TerionProcessor) };