@@ -38,6 +38,7 @@ void SpectrumAnalyzerState::initializeFifo()
3838{
3939 fftDataReady = false ;
4040 fifoSize = fftSize * 4 ;
41+ hopSize = static_cast <int > (fftSize * (1 .0f - overlapFactor));
4142
4243 audioFifo = std::make_unique<AbstractFifo> (fifoSize);
4344
@@ -57,7 +58,7 @@ void SpectrumAnalyzerState::pushSample (float sample) noexcept
5758 if (writeScope.blockSize1 > 0 )
5859 sampleBuffer[static_cast <size_t > (writeScope.startIndex1 )] = sample;
5960
60- // Check if we have enough samples for FFT processing
61+ // Check if we have enough samples for FFT processing with overlap
6162 if (audioFifo->getNumReady () >= fftSize)
6263 fftDataReady = true ;
6364}
@@ -85,7 +86,7 @@ void SpectrumAnalyzerState::pushSamples (const float* samples, int numSamples) n
8586 std::copy_n (samples + writeScope.blockSize1 , writeScope.blockSize2 , &sampleBuffer[static_cast <size_t > (writeScope.startIndex2 )]);
8687 }
8788
88- // Check if we have enough samples for FFT processing
89+ // Check if we have enough samples for FFT processing with overlap
8990 if (audioFifo->getNumReady () >= fftSize)
9091 fftDataReady = true ;
9192}
@@ -103,29 +104,42 @@ bool SpectrumAnalyzerState::getFFTData (float* destBuffer) noexcept
103104 if (destBuffer == nullptr || ! isFFTDataReady ())
104105 return false ;
105106
106- // Lock-free read from FIFO - safe for UI thread
107- const auto readScope = audioFifo->read (fftSize);
107+ // Use prepareToRead to get read positions without consuming data
108+ int startIndex1, blockSize1, startIndex2, blockSize2;
109+ audioFifo->prepareToRead (fftSize, startIndex1, blockSize1, startIndex2, blockSize2);
108110
109111 // Copy first block
110- if (readScope. blockSize1 > 0 )
112+ if (blockSize1 > 0 )
111113 {
112- std::copy_n (&sampleBuffer[static_cast <size_t > (readScope. startIndex1 )],
113- readScope. blockSize1 ,
114+ std::copy_n (&sampleBuffer[static_cast <size_t > (startIndex1)],
115+ blockSize1,
114116 destBuffer);
115117 }
116118
117119 // Copy second block (wrap-around case)
118- if (readScope. blockSize2 > 0 )
120+ if (blockSize2 > 0 )
119121 {
120- std::copy_n (&sampleBuffer[static_cast <size_t > (readScope. startIndex2 )],
121- readScope. blockSize2 ,
122- destBuffer + readScope. blockSize1 );
122+ std::copy_n (&sampleBuffer[static_cast <size_t > (startIndex2)],
123+ blockSize2,
124+ destBuffer + blockSize1);
123125 }
124126
125- // Reset the ready flag since we've consumed the data
126- fftDataReady = false ;
127+ // Check if we read the full FFT size
128+ const int actualReadSize = blockSize1 + blockSize2;
129+ if (actualReadSize == fftSize)
130+ {
131+ // Advance read position by hopSize (not full FFT size) for overlap processing
132+ audioFifo->finishedRead (hopSize);
133+
134+ // Check if we still have enough samples for next FFT
135+ fftDataReady = (audioFifo->getNumReady () >= fftSize);
136+
137+ return true ;
138+ }
127139
128- return (readScope.blockSize1 + readScope.blockSize2 ) == fftSize;
140+ // If we couldn't read the full FFT size, reset flag and return false
141+ fftDataReady = false ;
142+ return false ;
129143}
130144
131145// ==============================================================================
@@ -161,4 +175,21 @@ int SpectrumAnalyzerState::getFreeSpace() const noexcept
161175 return audioFifo->getFreeSpace ();
162176}
163177
178+ void SpectrumAnalyzerState::setOverlapFactor (float newOverlapFactor)
179+ {
180+ jassert (newOverlapFactor >= 0 .0f && newOverlapFactor < 1 .0f );
181+
182+ if (overlapFactor != newOverlapFactor)
183+ {
184+ overlapFactor = jlimit (0 .0f , 0 .95f , newOverlapFactor);
185+ hopSize = static_cast <int > (fftSize * (1 .0f - overlapFactor));
186+ hopSize = jmax (1 , hopSize); // Ensure minimum hop size of 1
187+ }
188+ }
189+
190+ int SpectrumAnalyzerState::getHopSize () const noexcept
191+ {
192+ return hopSize;
193+ }
194+
164195} // namespace yup
0 commit comments