···258258259259**Test Results**: Basic API working, visualization shows 10 octaves with test data mapping
260260261261-#### Phase 2: Real CQT Processing (Priority Tasks)
262262-1. **Access raw audio buffer** from FFT capture system
263263-2. **Implement 4096-point FFT** for CQT (separate from main FFT)
264264-3. **Apply CQT kernels** to FFT output (currently stubbed)
265265-4. **Fix kernel initialization** - kernels not being generated on startup
266266-5. **Add remaining API functions**: `cqts()`, `cqto()`, `cqtos()`
267267-6. **Create comparison demo** showing FFT vs CQT side-by-side
261261+#### Phase 2: Real CQT Processing (DEBUGGING)
262262+1. ✓ **Access raw audio buffer** from FFT capture system
263263+2. ✓ **Implement 4096-point FFT** for CQT (separate from main FFT)
264264+3. ✓ **Apply CQT kernels** to FFT output
265265+4. ✓ **Fix kernel initialization** - kernels are properly generated on startup
266266+5. **Add remaining API functions**: `cqts()`, `cqto()`, `cqtos()` (TODO)
267267+6. **Create comparison demo** showing FFT vs CQT side-by-side (TODO)
268268+269269+**TEMPORARY CHANGE**: FFT_SIZE has been changed from 1024 to 2048 in fftdata.h to support CQT's 4096-point FFT requirement. This temporarily breaks FFT resolution (now 2048 bins instead of 1024) but allows CQT to function properly. This should be reverted once a separate audio buffer is implemented for CQT.
270270+271271+**CURRENT ISSUE**: CQT frequency mapping is incorrect. Test shows:
272272+- Playing 110 Hz (A2) appears at bin 0-4 instead of expected bin 30
273273+- Error of ~26-30 bins (2-3 octaves too low)
274274+- CQT is detecting signals but at wrong frequency bins
275275+276276+**Debugging Status**:
277277+1. Changed smoothing from 0.7 to 0.3 - improved peak sharpness ✓
278278+2. Fixed window length calculation to use Q factor ✓
279279+3. Fixed kernel generation to use equal temperament spacing ✓
280280+4. Added gain boost (4x) for better visibility ✓
281281+5. Created test scripts: test_cqt_tone.lua, test_cqt_debug.lua ✓
282282+6. **FIXED kernel phase calculation** - Critical fix! ✓
283283+ - Problem: Was using `(i - windowLength/2) / sampleRate` for phase
284284+ - Solution: Use `(idx - fftSize/2) * (centerFreq / sampleRate)` like ESP32
285285+ - The modulation must be based on position in full FFT buffer, not window
286286+287287+**Key Fix Applied**:
288288+```c
289289+// OLD (incorrect):
290290+float t = (i - windowLength/2.0f) / sampleRate;
291291+float phase = 2.0f * M_PI * centerFreq * t;
292292+293293+// NEW (correct - matches ESP32):
294294+float phase = 2.0f * M_PI * (centerFreq / sampleRate) * (idx - fftSize/2);
295295+```
296296+297297+This should fix the frequency mapping issue. Ready for testing!
298298+299299+**Update after testing**:
300300+- The phase fix helped but frequencies are still mapping to wrong bins
301301+- 110 Hz appears at bin 3 instead of 30 (27-bin error)
302302+- Created test_cqt_stable.lua for controlled testing
303303+- Created test_cqt_a4.lua for constant 440Hz tone
304304+- Added debug output to show kernel FFT bin ranges
305305+- Issue appears to be in kernel generation or application
306306+307307+**Current hypothesis**:
308308+The kernels might be centered at the wrong FFT bins. Need to verify:
309309+1. The FFT bin calculation for each center frequency
310310+2. The kernel's actual FFT bin coverage
311311+3. Whether the complex multiplication is being done correctly
312312+313313+**Issues found**:
314314+1. Audio generation in test cart was wrong - fixed in test_cqt_a4.lua
315315+2. Added debug output to show:
316316+ - FFT bin magnitudes around 440 Hz (should peak at bin 41)
317317+ - Which CQT bins have high values
318318+ - This will help identify if the issue is in kernel generation or application
319319+320320+**To test**:
321321+Build and run with test_cqt_a4.lua. The console should show:
322322+- Every second: FFT bins around 440 Hz and active CQT bins
323323+- This will reveal if 440 Hz is detected at FFT bin 41 but mapped to wrong CQT bin
324324+325325+**Debug results**:
326326+- FFT correctly shows 440 Hz peak at bin 41 (magnitude 730) ✓
327327+- CQT bin 54 has high value (27595) which is correct for 440 Hz ✓
328328+- BUT: Almost ALL CQT bins (0-105) have significant energy
329329+- This means kernels are not frequency-selective enough
330330+331331+**Fix applied**:
332332+- Changed normalization to match ESP32: divide by windowLength before FFT
333333+- Added scaling factor after FFT: multiply by centerFreq/minFreq
334334+- This should make kernels more frequency-selective
335335+336336+**Test results after fix**:
337337+- 440 Hz correctly peaks at CQT bin 54 ✓
338338+- BUT: ALL bins (0-119) have significant values
339339+- High frequency bins (90-119) have values in thousands!
340340+- This means kernels are not properly bandpass filtered
341341+342342+**New hypothesis**:
343343+The issue is that our kernels are "seeing" all frequencies. Possible causes:
344344+1. The modulation in time domain might be creating aliases
345345+2. The window might be too wide or too narrow
346346+3. The FFT of the kernel might need different normalization
347347+348348+**Next debugging steps**:
349349+- Removed scaling factor (made it worse)
350350+- Added debug to show kernel 54's FFT bin range
351351+- Need to verify kernels are properly bandpass filtered around their center frequencies
352352+353353+**SOLUTION FOUND**:
354354+- Removed the scaling factor - this was the key fix!
355355+- Kernel 54 now correctly uses only 9 FFT bins (38-46) centered on bin 41
356356+- 440 Hz correctly peaks at CQT bin 54 with magnitude 681
357357+- Only ~50 bins have values > 0.1 (vs all 120 before)
358358+- CQT is now properly frequency-selective!
359359+360360+**Working implementation**:
361361+- Kernels use Q-factor based window length
362362+- Normalize by windowLength before FFT
363363+- NO scaling factor after FFT
364364+- Proper phase calculation: `2π * (f/fs) * (idx - N/2)`
268365269366#### Phase 3: Optimization (If needed)
2703671. Profile and identify bottlenecks
+3-26
src/core/core.c
···445445 {
446446 FFT_GetFFT(fftData);
447447448448- // Process CQT using existing FFT data
448448+ // Process CQT using raw audio buffer
449449 // For now, tie CQT to FFT enable flag
450450 cqtEnabled = fftEnabled;
451451 if (cqtEnabled)
452452 {
453453- // TODO: In a full implementation, we would:
454454- // 1. Get raw audio samples
455455- // 2. Perform our own 4096-point FFT
456456- // 3. Apply CQT kernels
457457- // For now, we'll use a simplified approach with existing FFT data
458458-459459- // TEMPORARY: Generate test data for Phase 1 testing
460460- // This creates a simple frequency sweep pattern
461461- for (int i = 0; i < CQT_BINS; i++)
462462- {
463463- // Use existing FFT data to create some movement
464464- int fftIndex = (i * FFT_SIZE) / CQT_BINS;
465465- if (fftIndex < FFT_SIZE)
466466- {
467467- // Map FFT data to CQT bins with some scaling
468468- cqtData[i] = fftData[fftIndex] * 0.5f;
469469-470470- // Apply smoothing
471471- cqtSmoothingData[i] = cqtSmoothingData[i] * 0.8f + cqtData[i] * 0.2f;
472472-473473- // Normalize
474474- cqtNormalizedData[i] = cqtSmoothingData[i];
475475- if (cqtNormalizedData[i] > 1.0f) cqtNormalizedData[i] = 1.0f;
476476- }
477477- }
453453+ // Process CQT from the shared audio buffer
454454+ CQT_ProcessAudio();
478455 }
479456 }
480457 if (!core->state.initialized)
+1-1
src/cqtdata.h
···1111#define CQT_MAX_FREQ 20480.0f // Nearest note to 20kHz
12121313// Smoothing parameters
1414-#define CQT_SMOOTHING_FACTOR 0.7f
1414+#define CQT_SMOOTHING_FACTOR 0.3f // Reduced from 0.7f for more responsive display
1515#define CQT_SPARSITY_THRESHOLD 0.01f
16161717// Raw CQT magnitude data
+192-9
src/ext/cqt.c
···22#include "cqt_kernel.h"
33#include "../cqtdata.h"
44#include "../fftdata.h"
55+#include "fft.h"
56#include "kiss_fftr.h"
67#include <math.h>
78#include <string.h>
99+#include <stdbool.h>
1010+#include <stdio.h>
1111+1212+#define CQT_DEBUG
813914// FFT configuration for CQT
1015static kiss_fftr_cfg cqtFftCfg = NULL;
···5358 return false;
5459 }
55606161+ // Debug: Print first few center frequencies and expected FFT bins
6262+ #ifdef CQT_DEBUG
6363+ float centerFreqs[CQT_BINS];
6464+ CQT_GenerateCenterFrequencies(centerFreqs, CQT_BINS, CQT_MIN_FREQ, CQT_MAX_FREQ);
6565+ printf("CQT: First 10 center frequencies:\n");
6666+ for (int i = 0; i < 10 && i < CQT_BINS; i++)
6767+ {
6868+ // FFT bin = freq * fftSize / sampleRate
6969+ int expectedBin = (int)(centerFreqs[i] * CQT_FFT_SIZE / 44100.0f);
7070+ printf(" Bin %d: %.2f Hz -> FFT bin %d\n", i, centerFreqs[i], expectedBin);
7171+ }
7272+7373+ // Also print expected bins for test frequencies
7474+ printf("\nCQT: Expected bins for test frequencies:\n");
7575+ float testFreqs[] = {110, 220, 440, 880};
7676+ for (int i = 0; i < 4; i++)
7777+ {
7878+ int cqtBin = (int)(12 * log(testFreqs[i] / 20.0) / log(2.0) + 0.5);
7979+ int fftBin = (int)(testFreqs[i] * CQT_FFT_SIZE / 44100.0f);
8080+ printf(" %.0f Hz -> CQT bin %d, FFT bin %d\n", testFreqs[i], cqtBin, fftBin);
8181+ }
8282+ #endif
8383+5684 return true;
5785}
5886···6694 for (int bin = 0; bin < CQT_BINS; bin++)
6795 {
6896 CqtKernel* kernel = &cqtKernels[bin];
9797+9898+ // Check if kernel is valid
9999+ if (!kernel->real || !kernel->imag || !kernel->indices || kernel->length == 0)
100100+ {
101101+ cqtData[bin] = 0.0f;
102102+ continue;
103103+ }
104104+69105 float real = 0.0f;
70106 float imag = 0.0f;
71107···73109 for (int k = 0; k < kernel->length; k++)
74110 {
75111 int idx = kernel->indices[k];
112112+ // Ensure index is within bounds
113113+ if (idx < 0 || idx > CQT_FFT_SIZE/2)
114114+ continue;
115115+76116 // Complex multiplication: (a + bi) * (c + di) = (ac - bd) + (ad + bc)i
77117 real += fftReal[idx] * kernel->real[k] - fftImag[idx] * kernel->imag[k];
78118 imag += fftReal[idx] * kernel->imag[k] + fftImag[idx] * kernel->real[k];
79119 }
801208181- // Calculate magnitude
8282- cqtData[bin] = sqrt(real * real + imag * imag);
121121+ // Calculate magnitude with gain boost
122122+ cqtData[bin] = sqrt(real * real + imag * imag) * 4.0f; // Increased gain boost
123123+124124+ // Check for NaN or Inf
125125+ if (!isfinite(cqtData[bin]))
126126+ cqtData[bin] = 0.0f;
127127+ }
128128+}
129129+130130+// Process CQT from audio data
131131+void CQT_ProcessAudio(void)
132132+{
133133+ if (!cqtFftCfg || !cqtEnabled) return;
134134+135135+ // Check if kernels are initialized
136136+ bool kernelsValid = false;
137137+ for (int i = 0; i < CQT_BINS; i++)
138138+ {
139139+ if (cqtKernels[i].real && cqtKernels[i].length > 0)
140140+ {
141141+ kernelsValid = true;
142142+ break;
143143+ }
144144+ }
145145+146146+ if (!kernelsValid)
147147+ {
148148+ // Kernels not initialized, set all output to zero
149149+ memset(cqtData, 0, sizeof(cqtData));
150150+ memset(cqtSmoothingData, 0, sizeof(cqtSmoothingData));
151151+ memset(cqtNormalizedData, 0, sizeof(cqtNormalizedData));
152152+ return;
153153+ }
154154+155155+ // Copy audio data from the shared buffer
156156+ // TEMPORARY: sampleBuf now has FFT_SIZE * 2 = 2048 * 2 = 4096 samples
157157+ memcpy(cqtAudioBuffer, sampleBuf, CQT_FFT_SIZE * sizeof(float));
158158+159159+ // Check if we have any audio data
160160+ float audioSum = 0.0f;
161161+ for (int i = 0; i < CQT_FFT_SIZE; i++)
162162+ {
163163+ audioSum += fabs(cqtAudioBuffer[i]);
164164+ }
165165+166166+ if (audioSum < 0.0001f)
167167+ {
168168+ // No audio data, set output to zero
169169+ memset(cqtData, 0, sizeof(cqtData));
170170+ memset(cqtSmoothingData, 0, sizeof(cqtSmoothingData));
171171+ memset(cqtNormalizedData, 0, sizeof(cqtNormalizedData));
172172+ return;
173173+ }
174174+175175+ // Perform 4096-point FFT
176176+ kiss_fftr(cqtFftCfg, cqtAudioBuffer, cqtFftOutput);
177177+178178+ // Extract real and imaginary components for kernel application
179179+ float fftReal[CQT_FFT_SIZE/2 + 1];
180180+ float fftImag[CQT_FFT_SIZE/2 + 1];
181181+182182+ for (int i = 0; i <= CQT_FFT_SIZE/2; i++)
183183+ {
184184+ fftReal[i] = cqtFftOutput[i].r;
185185+ fftImag[i] = cqtFftOutput[i].i;
186186+ }
187187+188188+ // Apply CQT kernels
189189+ CQT_ApplyKernels(fftReal, fftImag);
190190+191191+ #ifdef CQT_DEBUG
192192+ // Reduced debug output - CQT is working correctly now
193193+ static int debugCounter = 0;
194194+ if (++debugCounter % 300 == 0) // Print once every 5 seconds
195195+ {
196196+ // Find peak CQT bin
197197+ int peakBin = 0;
198198+ float peakVal = 0.0f;
199199+ for (int i = 0; i < CQT_BINS; i++)
200200+ {
201201+ if (cqtData[i] > peakVal)
202202+ {
203203+ peakVal = cqtData[i];
204204+ peakBin = i;
205205+ }
206206+ }
207207+208208+ if (peakVal > 1.0f)
209209+ {
210210+ float peakFreq = CQT_MIN_FREQ * pow(2.0f, peakBin / 12.0f);
211211+ printf("CQT: Peak at bin %d (%.1f Hz) with magnitude %.1f\n",
212212+ peakBin, peakFreq, peakVal);
213213+ }
214214+ }
215215+ #endif
216216+217217+ // Apply smoothing
218218+ for (int i = 0; i < CQT_BINS; i++)
219219+ {
220220+ cqtSmoothingData[i] = cqtSmoothingData[i] * CQT_SMOOTHING_FACTOR +
221221+ cqtData[i] * (1.0f - CQT_SMOOTHING_FACTOR);
222222+ }
223223+224224+ // Find peak for normalization
225225+ float currentPeak = 0.0f;
226226+ for (int i = 0; i < CQT_BINS; i++)
227227+ {
228228+ if (cqtSmoothingData[i] > currentPeak)
229229+ currentPeak = cqtSmoothingData[i];
230230+ }
231231+232232+ // Initialize peak value if needed
233233+ if (cqtPeakSmoothValue <= 0.0f)
234234+ cqtPeakSmoothValue = 0.1f;
235235+236236+ // Smooth peak value
237237+ if (currentPeak > cqtPeakSmoothValue)
238238+ cqtPeakSmoothValue = currentPeak;
239239+ else
240240+ cqtPeakSmoothValue = cqtPeakSmoothValue * 0.99f + currentPeak * 0.01f;
241241+242242+ // Ensure peak value doesn't go too low
243243+ if (cqtPeakSmoothValue < 0.0001f)
244244+ cqtPeakSmoothValue = 0.0001f;
245245+246246+ // Normalize data
247247+ float normalizer = 1.0f / cqtPeakSmoothValue;
248248+ for (int i = 0; i < CQT_BINS; i++)
249249+ {
250250+ cqtNormalizedData[i] = cqtSmoothingData[i] * normalizer;
251251+ if (cqtNormalizedData[i] > 1.0f)
252252+ cqtNormalizedData[i] = 1.0f;
253253+254254+ // Final NaN check
255255+ if (!isfinite(cqtNormalizedData[i]))
256256+ cqtNormalizedData[i] = 0.0f;
83257 }
84258}
8525986260// Process CQT from audio data (using existing FFT data from fftdata.h)
261261+// This is kept for backward compatibility, but not used
87262void CQT_Process(const float* fftReal, const float* fftImag)
88263{
89264 if (!cqtFftCfg || !cqtEnabled) return;
902659191- // Note: In the full implementation, we would:
9292- // 1. Get audio data from the shared buffer
9393- // 2. Perform our own 4096-point FFT
9494- // For now, we'll process using provided FFT data
9595-96266 // Apply CQT kernels
97267 CQT_ApplyKernels(fftReal, fftImag);
98268···111281 currentPeak = cqtSmoothingData[i];
112282 }
113283284284+ // Initialize peak value if needed
285285+ if (cqtPeakSmoothValue <= 0.0f)
286286+ cqtPeakSmoothValue = 0.1f;
287287+114288 // Smooth peak value
115289 if (currentPeak > cqtPeakSmoothValue)
116290 cqtPeakSmoothValue = currentPeak;
117291 else
118292 cqtPeakSmoothValue = cqtPeakSmoothValue * 0.99f + currentPeak * 0.01f;
119293294294+ // Ensure peak value doesn't go too low
295295+ if (cqtPeakSmoothValue < 0.0001f)
296296+ cqtPeakSmoothValue = 0.0001f;
297297+120298 // Normalize data
121121- float normalizer = (cqtPeakSmoothValue > 0.0001f) ? (1.0f / cqtPeakSmoothValue) : 1.0f;
299299+ float normalizer = 1.0f / cqtPeakSmoothValue;
122300 for (int i = 0; i < CQT_BINS; i++)
123301 {
124302 cqtNormalizedData[i] = cqtSmoothingData[i] * normalizer;
125125- if (cqtNormalizedData[i] > 1.0f) cqtNormalizedData[i] = 1.0f;
303303+ if (cqtNormalizedData[i] > 1.0f)
304304+ cqtNormalizedData[i] = 1.0f;
305305+306306+ // Final NaN check
307307+ if (!isfinite(cqtNormalizedData[i]))
308308+ cqtNormalizedData[i] = 0.0f;
126309 }
127310}
128311
+4-1
src/ext/cqt.h
···66// Returns true on success, false on failure
77bool CQT_Open(void);
8899-// Process CQT from FFT data
99+// Process CQT from audio buffer (uses shared audio capture buffer)
1010+void CQT_ProcessAudio(void);
1111+1212+// Process CQT from FFT data (legacy)
1013// fftData: Complex FFT output (size should be CQT_FFT_SIZE/2 + 1)
1114void CQT_Process(const float* fftReal, const float* fftImag);
1215
+61-15
src/ext/cqt_kernel.c
···11#include "cqt_kernel.h"
22+#include "../cqtdata.h"
23#include <math.h>
34#include <stdlib.h>
45#include <string.h>
···89#define M_PI 3.14159265358979323846
910#endif
10111111-// Generate logarithmically spaced center frequencies
1212+// Generate logarithmically spaced center frequencies for musical notes
1213void CQT_GenerateCenterFrequencies(float* frequencies, int numBins, float minFreq, float maxFreq)
1314{
1414- float logRatio = log(maxFreq / minFreq);
1515+ // For musical CQT with 12 bins per octave, we want equal temperament spacing
1616+ // Each semitone is a factor of 2^(1/12) ≈ 1.0594631
1717+ const float semitone = pow(2.0f, 1.0f / 12.0f);
1818+1519 for (int i = 0; i < numBins; i++)
1620 {
1717- frequencies[i] = minFreq * exp(logRatio * i / (numBins - 1));
2121+ // Calculate frequency for each bin based on semitone spacing
2222+ frequencies[i] = minFreq * pow(semitone, i);
2323+ }
2424+2525+ // Verify we don't exceed maxFreq
2626+ if (frequencies[numBins - 1] > maxFreq)
2727+ {
2828+ // Scale down if necessary
2929+ float scale = maxFreq / frequencies[numBins - 1];
3030+ for (int i = 0; i < numBins; i++)
3131+ {
3232+ frequencies[i] *= scale;
3333+ }
1834 }
1935}
2036···6379 CqtWindowType windowType,
6480 float sparsityThreshold)
6581{
6666- // Calculate window length based on frequency (inverse relationship)
6767- float factor = centerFreq / minFreq;
6868- int windowLength = (int)(fftSize / factor);
6969- if (windowLength < 1) windowLength = 1;
8282+ // Calculate window length based on Q factor
8383+ // windowLength = Q * sampleRate / centerFreq
8484+ // This gives us the proper frequency resolution
8585+ float Q = CQT_CalculateQ(CQT_BINS_PER_OCTAVE);
8686+ int windowLength = (int)(Q * sampleRate / centerFreq);
8787+8888+ // Ensure window length is reasonable
8989+ if (windowLength < 32) windowLength = 32; // Minimum window size
7090 if (windowLength > fftSize) windowLength = fftSize;
71917292 // Allocate temporary arrays
···8210283103 // Generate window in the center of the kernel
84104 int windowStart = (fftSize - windowLength) / 2;
8585- float* window = &timeKernel[windowStart];
105105+106106+ // First generate the window
107107+ float* tempWindow = (float*)malloc(windowLength * sizeof(float));
108108+ if (!tempWindow)
109109+ {
110110+ free(timeKernel);
111111+ free(freqKernel);
112112+ return false;
113113+ }
8611487115 switch (windowType)
88116 {
89117 case CQT_WINDOW_HAMMING:
9090- generateHammingWindow(window, windowLength);
118118+ generateHammingWindow(tempWindow, windowLength);
91119 break;
92120 case CQT_WINDOW_GAUSSIAN:
9393- generateGaussianWindow(window, windowLength);
121121+ generateGaussianWindow(tempWindow, windowLength);
94122 break;
95123 }
961249797- // Modulate window with complex exponential
9898- for (int i = 0; i < fftSize; i++)
125125+ // Apply window and modulate with complex exponential
126126+ // Following ESP32 reference: modulate based on full FFT size, not window size
127127+ for (int i = 0; i < windowLength; i++)
99128 {
100100- float phase = 2.0f * M_PI * centerFreq / sampleRate * (i - fftSize / 2);
101101- timeKernel[i] *= cos(phase);
129129+ int idx = windowStart + i;
130130+ // Key insight: use idx (position in full FFT buffer) not i (position in window)
131131+ // and center around N/2 where N is the full FFT size
132132+ float phase = 2.0f * M_PI * (centerFreq / sampleRate) * (idx - fftSize/2);
133133+ timeKernel[idx] = tempWindow[i] * cos(phase);
102134 }
103135104104- // Normalize by window length
136136+ // Normalize by window length before FFT (like ESP32)
105137 for (int i = 0; i < fftSize; i++)
106138 {
107139 timeKernel[i] /= windowLength;
108140 }
141141+142142+ free(tempWindow);
109143110144 // Perform FFT
111145 kiss_fftr(fftCfg, timeKernel, freqKernel);
···140174141175 // Store non-zero elements
142176 int sparseIndex = 0;
177177+ int minIdx = fftSize, maxIdx = 0; // Track range for debug
143178 for (int i = 0; i <= fftSize/2; i++)
144179 {
145180 float magnitude = sqrt(freqKernel[i].r * freqKernel[i].r +
···149184 kernel->real[sparseIndex] = freqKernel[i].r;
150185 kernel->imag[sparseIndex] = freqKernel[i].i;
151186 kernel->indices[sparseIndex] = i;
187187+ if (i < minIdx) minIdx = i;
188188+ if (i > maxIdx) maxIdx = i;
152189 sparseIndex++;
153190 }
154191 }
192192+193193+ #ifdef CQT_DEBUG
194194+ // Debug output for specific frequencies
195195+ if (fabs(centerFreq - 110.0f) < 1.0f || fabs(centerFreq - 440.0f) < 1.0f)
196196+ {
197197+ printf("Kernel for %.1f Hz: FFT bins %d-%d (count: %d)\n",
198198+ centerFreq, minIdx, maxIdx, nonZeroCount);
199199+ }
200200+ #endif
155201156202 free(timeKernel);
157203 free(freqKernel);
+2
src/ext/fft.c
···186186187187 memset(sampleBuf, 0, sizeof(float) * FFT_SIZE * 2);
188188189189+ // TEMPORARY: Using 4096-point FFT to support CQT
190190+ // TODO: Restore to 2048 and implement separate buffer for CQT
189191 fftcfg = kiss_fftr_alloc(FFT_SIZE * 2, false, NULL, NULL);
190192191193 ma_context_config context_config = ma_context_config_init();
+3
src/ext/fft.h
···88void FFT_GetFFT(float* _samples);
99void FFT_Close();
10101111+// CQT needs access to the raw audio buffer
1212+extern float sampleBuf[];
1313+1114//////////////////////////////////////////////////////////////////////////
+4-1
src/fftdata.h
···11#pragma once
22#include <stdbool.h>
33-#define FFT_SIZE 1024
33+// TEMPORARY: Changed from 1024 to 2048 to support CQT's 4096-point FFT
44+// This breaks FFT bin resolution but enables CQT to work properly
55+// TODO: Restore to 1024 and implement separate buffer for CQT
66+#define FFT_SIZE 2048
47extern float fPeakMinValue;
58extern float fPeakSmoothing;
69extern float fPeakSmoothValue;