3636#include " globals.h"
3737#include < algorithm>
3838#include < numeric>
39+ #include < array>
3940#include < arduinoFFT.h>
4041#include < driver/adc.h>
4142#include < driver/i2s.h>
@@ -348,8 +349,8 @@ class SoundAnalyzer : public ISoundAnalyzer
348349 float _oldVU; // Old VU value for damping
349350 float _oldPeakVU; // Old peak VU value for damping
350351 float _oldMinVU; // Old min VU value for damping
351- float * _vPeaks; // Normalized band energies 0..1
352- float * _livePeaks; // Attack-limited display peaks per band
352+ std::array< float , NUM_BANDS > _vPeaks{}; // Normalized band energies 0..1
353+ std::array< float , NUM_BANDS > _livePeaks{}; // Attack-limited display peaks per band
353354 int _bandBinStart[NUM_BANDS ];
354355 int _bandBinEnd[NUM_BANDS ];
355356 float _energyMaxEnv = 0 .01f ; // adaptive envelope for autoscaling (start low for fast adaptation)
@@ -373,28 +374,25 @@ class SoundAnalyzer : public ISoundAnalyzer
373374
374375 private:
375376 static constexpr int kBandOffset = 2 ; // number of lowest source bands to skip in layout (skip bins 0,1,2)
376- float *_vReal = nullptr ;
377- float *_vImaginary = nullptr ;
377+ std::array< float , MAX_SAMPLES > _vReal{} ;
378+ std::array< float , MAX_SAMPLES > _vImaginary{} ;
378379 std::unique_ptr<int16_t []> ptrSampleBuffer; // sample buffer storage
379380 PeakData _Peaks; // cached last normalized peaks (moved earlier for inline method visibility)
380381
381382 // Reset and clear the FFT buffers
382383
383384 void Reset ()
384385 {
385- if (!_vReal)
386- return ;
387- std::fill_n (_vReal, MAX_SAMPLES , 0 .0f );
388- if (_vImaginary)
389- std::fill_n (_vImaginary, MAX_SAMPLES , 0 .0f );
390- std::fill_n (_vPeaks, NUM_BANDS , 0 .0f );
386+ _vReal.fill (0 .0f );
387+ _vImaginary.fill (0 .0f );
388+ _vPeaks.fill (0 .0f );
391389 }
392390
393391 // Perform the FFT
394392
395393 void FFT ()
396394 {
397- ArduinoFFT<float > _FFT (_vReal, _vImaginary, MAX_SAMPLES , SAMPLING_FREQUENCY );
395+ ArduinoFFT<float > _FFT (_vReal. data () , _vImaginary. data () , MAX_SAMPLES , SAMPLING_FREQUENCY );
398396 _FFT.dcRemoval ();
399397 _FFT.windowing (FFTWindow::Hann, FFTDirection::Forward);
400398 _FFT.compute (FFTDirection::Forward);
@@ -572,12 +570,8 @@ class SoundAnalyzer : public ISoundAnalyzer
572570 // Use reciprocal of AudioFPS for frame-rate independent attack limiting
573571 float dt = (_AudioFPS > 0 ) ? (1 .0f / (float )_AudioFPS) : 0 .016f ;
574572 // Fallback to reasonable default if FPS is invalid
575- if (dt <= 0 .0f || dt > 0 .1f ) dt = 0 .016f ;
576- // Allocate _livePeaks if not already done
577- if (!_livePeaks) {
578- _livePeaks = (float *)PreferPSRAMAlloc (NUM_BANDS * sizeof (_livePeaks[0 ]));
579- for (int i = 0 ; i < NUM_BANDS ; ++i) _livePeaks[i] = 0 .0f ;
580- }
573+ if (dt <= 0 .0f || dt > 0 .1f )
574+ dt = 0 .016f ;
581575 _framesProcessed++;
582576 const float binWidth = (float )SAMPLING_FREQUENCY / (MAX_SAMPLES / 2 .0f );
583577 for (int b = 0 ; b < NUM_BANDS ; b++)
@@ -862,13 +856,7 @@ class SoundAnalyzer : public ISoundAnalyzer
862856 ptrSampleBuffer.reset ((int16_t *)heap_caps_malloc (MAX_SAMPLES * sizeof (int16_t ), MALLOC_CAP_8BIT ));
863857 if (!ptrSampleBuffer)
864858 throw std::runtime_error (" Failed to allocate sample buffer" );
865- _vReal = (float *)PreferPSRAMAlloc (MAX_SAMPLES * sizeof (_vReal[0 ]));
866- _vImaginary = (float *)PreferPSRAMAlloc (MAX_SAMPLES * sizeof (_vImaginary[0 ]));
867- _vPeaks = (float *)PreferPSRAMAlloc (NUM_BANDS * sizeof (_vPeaks[0 ]));
868- _livePeaks = (float *)PreferPSRAMAlloc (NUM_BANDS * sizeof (_livePeaks[0 ]));
869- if (!_vReal || !_vImaginary || !_vPeaks || !_livePeaks)
870- throw std::runtime_error (" Failed to allocate FFT buffers" );
871- for (int i = 0 ; i < NUM_BANDS ; ++i) _livePeaks[i] = 0 .0f ;
859+ // No dynamic allocations needed for FFT/peak arrays
872860 _oldVU = _oldPeakVU = _oldMinVU = 0 .0f ;
873861 // No runtime parameter initialization needed - all compile-time now
874862 ComputeBandLayout ();
@@ -885,10 +873,7 @@ class SoundAnalyzer : public ISoundAnalyzer
885873 i2s_stop (I2S_NUM_0 );
886874 i2s_driver_uninstall (I2S_NUM_0 );
887875#endif
888- free (_vReal);
889- free (_vImaginary);
890- free (_vPeaks);
891- free (_livePeaks);
876+ // No heap frees required for std::array members
892877 }
893878
894879 // These functions allow access to the last-acquired sample buffer and its size so that
@@ -1071,8 +1056,8 @@ class SoundAnalyzer : public ISoundAnalyzer
10711056 {
10721057 _msLastRemoteAudio = millis ();
10731058 _Peaks = peaks;
1074- std::copy (&_Peaks._Level [0 ], &_Peaks._Level [0 ] + NUM_BANDS , _vPeaks);
1075- float sum = std::accumulate (_vPeaks, _vPeaks + NUM_BANDS , 0 .0f );
1059+ std::copy (&_Peaks._Level [0 ], &_Peaks._Level [0 ] + NUM_BANDS , _vPeaks. data () );
1060+ float sum = std::accumulate (_vPeaks. begin () , _vPeaks. end () , 0 .0f );
10761061 UpdateVU (sum / NUM_BANDS );
10771062 }
10781063
0 commit comments