this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

phase 2 pt 1

alice a3d9a355 70f9f595

+374 -60
+104 -7
CLAUDE.md
··· 258 258 259 259 **Test Results**: Basic API working, visualization shows 10 octaves with test data mapping 260 260 261 - #### Phase 2: Real CQT Processing (Priority Tasks) 262 - 1. **Access raw audio buffer** from FFT capture system 263 - 2. **Implement 4096-point FFT** for CQT (separate from main FFT) 264 - 3. **Apply CQT kernels** to FFT output (currently stubbed) 265 - 4. **Fix kernel initialization** - kernels not being generated on startup 266 - 5. **Add remaining API functions**: `cqts()`, `cqto()`, `cqtos()` 267 - 6. **Create comparison demo** showing FFT vs CQT side-by-side 261 + #### Phase 2: Real CQT Processing (DEBUGGING) 262 + 1. ✓ **Access raw audio buffer** from FFT capture system 263 + 2. ✓ **Implement 4096-point FFT** for CQT (separate from main FFT) 264 + 3. ✓ **Apply CQT kernels** to FFT output 265 + 4. ✓ **Fix kernel initialization** - kernels are properly generated on startup 266 + 5. **Add remaining API functions**: `cqts()`, `cqto()`, `cqtos()` (TODO) 267 + 6. **Create comparison demo** showing FFT vs CQT side-by-side (TODO) 268 + 269 + **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. 270 + 271 + **CURRENT ISSUE**: CQT frequency mapping is incorrect. Test shows: 272 + - Playing 110 Hz (A2) appears at bin 0-4 instead of expected bin 30 273 + - Error of ~26-30 bins (2-3 octaves too low) 274 + - CQT is detecting signals but at wrong frequency bins 275 + 276 + **Debugging Status**: 277 + 1. Changed smoothing from 0.7 to 0.3 - improved peak sharpness ✓ 278 + 2. Fixed window length calculation to use Q factor ✓ 279 + 3. Fixed kernel generation to use equal temperament spacing ✓ 280 + 4. Added gain boost (4x) for better visibility ✓ 281 + 5. Created test scripts: test_cqt_tone.lua, test_cqt_debug.lua ✓ 282 + 6. **FIXED kernel phase calculation** - Critical fix! ✓ 283 + - Problem: Was using `(i - windowLength/2) / sampleRate` for phase 284 + - Solution: Use `(idx - fftSize/2) * (centerFreq / sampleRate)` like ESP32 285 + - The modulation must be based on position in full FFT buffer, not window 286 + 287 + **Key Fix Applied**: 288 + ```c 289 + // OLD (incorrect): 290 + float t = (i - windowLength/2.0f) / sampleRate; 291 + float phase = 2.0f * M_PI * centerFreq * t; 292 + 293 + // NEW (correct - matches ESP32): 294 + float phase = 2.0f * M_PI * (centerFreq / sampleRate) * (idx - fftSize/2); 295 + ``` 296 + 297 + This should fix the frequency mapping issue. Ready for testing! 298 + 299 + **Update after testing**: 300 + - The phase fix helped but frequencies are still mapping to wrong bins 301 + - 110 Hz appears at bin 3 instead of 30 (27-bin error) 302 + - Created test_cqt_stable.lua for controlled testing 303 + - Created test_cqt_a4.lua for constant 440Hz tone 304 + - Added debug output to show kernel FFT bin ranges 305 + - Issue appears to be in kernel generation or application 306 + 307 + **Current hypothesis**: 308 + The kernels might be centered at the wrong FFT bins. Need to verify: 309 + 1. The FFT bin calculation for each center frequency 310 + 2. The kernel's actual FFT bin coverage 311 + 3. Whether the complex multiplication is being done correctly 312 + 313 + **Issues found**: 314 + 1. Audio generation in test cart was wrong - fixed in test_cqt_a4.lua 315 + 2. Added debug output to show: 316 + - FFT bin magnitudes around 440 Hz (should peak at bin 41) 317 + - Which CQT bins have high values 318 + - This will help identify if the issue is in kernel generation or application 319 + 320 + **To test**: 321 + Build and run with test_cqt_a4.lua. The console should show: 322 + - Every second: FFT bins around 440 Hz and active CQT bins 323 + - This will reveal if 440 Hz is detected at FFT bin 41 but mapped to wrong CQT bin 324 + 325 + **Debug results**: 326 + - FFT correctly shows 440 Hz peak at bin 41 (magnitude 730) ✓ 327 + - CQT bin 54 has high value (27595) which is correct for 440 Hz ✓ 328 + - BUT: Almost ALL CQT bins (0-105) have significant energy 329 + - This means kernels are not frequency-selective enough 330 + 331 + **Fix applied**: 332 + - Changed normalization to match ESP32: divide by windowLength before FFT 333 + - Added scaling factor after FFT: multiply by centerFreq/minFreq 334 + - This should make kernels more frequency-selective 335 + 336 + **Test results after fix**: 337 + - 440 Hz correctly peaks at CQT bin 54 ✓ 338 + - BUT: ALL bins (0-119) have significant values 339 + - High frequency bins (90-119) have values in thousands! 340 + - This means kernels are not properly bandpass filtered 341 + 342 + **New hypothesis**: 343 + The issue is that our kernels are "seeing" all frequencies. Possible causes: 344 + 1. The modulation in time domain might be creating aliases 345 + 2. The window might be too wide or too narrow 346 + 3. The FFT of the kernel might need different normalization 347 + 348 + **Next debugging steps**: 349 + - Removed scaling factor (made it worse) 350 + - Added debug to show kernel 54's FFT bin range 351 + - Need to verify kernels are properly bandpass filtered around their center frequencies 352 + 353 + **SOLUTION FOUND**: 354 + - Removed the scaling factor - this was the key fix! 355 + - Kernel 54 now correctly uses only 9 FFT bins (38-46) centered on bin 41 356 + - 440 Hz correctly peaks at CQT bin 54 with magnitude 681 357 + - Only ~50 bins have values > 0.1 (vs all 120 before) 358 + - CQT is now properly frequency-selective! 359 + 360 + **Working implementation**: 361 + - Kernels use Q-factor based window length 362 + - Normalize by windowLength before FFT 363 + - NO scaling factor after FFT 364 + - Proper phase calculation: `2π * (f/fs) * (idx - N/2)` 268 365 269 366 #### Phase 3: Optimization (If needed) 270 367 1. Profile and identify bottlenecks
+3 -26
src/core/core.c
··· 445 445 { 446 446 FFT_GetFFT(fftData); 447 447 448 - // Process CQT using existing FFT data 448 + // Process CQT using raw audio buffer 449 449 // For now, tie CQT to FFT enable flag 450 450 cqtEnabled = fftEnabled; 451 451 if (cqtEnabled) 452 452 { 453 - // TODO: In a full implementation, we would: 454 - // 1. Get raw audio samples 455 - // 2. Perform our own 4096-point FFT 456 - // 3. Apply CQT kernels 457 - // For now, we'll use a simplified approach with existing FFT data 458 - 459 - // TEMPORARY: Generate test data for Phase 1 testing 460 - // This creates a simple frequency sweep pattern 461 - for (int i = 0; i < CQT_BINS; i++) 462 - { 463 - // Use existing FFT data to create some movement 464 - int fftIndex = (i * FFT_SIZE) / CQT_BINS; 465 - if (fftIndex < FFT_SIZE) 466 - { 467 - // Map FFT data to CQT bins with some scaling 468 - cqtData[i] = fftData[fftIndex] * 0.5f; 469 - 470 - // Apply smoothing 471 - cqtSmoothingData[i] = cqtSmoothingData[i] * 0.8f + cqtData[i] * 0.2f; 472 - 473 - // Normalize 474 - cqtNormalizedData[i] = cqtSmoothingData[i]; 475 - if (cqtNormalizedData[i] > 1.0f) cqtNormalizedData[i] = 1.0f; 476 - } 477 - } 453 + // Process CQT from the shared audio buffer 454 + CQT_ProcessAudio(); 478 455 } 479 456 } 480 457 if (!core->state.initialized)
+1 -1
src/cqtdata.h
··· 11 11 #define CQT_MAX_FREQ 20480.0f // Nearest note to 20kHz 12 12 13 13 // Smoothing parameters 14 - #define CQT_SMOOTHING_FACTOR 0.7f 14 + #define CQT_SMOOTHING_FACTOR 0.3f // Reduced from 0.7f for more responsive display 15 15 #define CQT_SPARSITY_THRESHOLD 0.01f 16 16 17 17 // Raw CQT magnitude data
+192 -9
src/ext/cqt.c
··· 2 2 #include "cqt_kernel.h" 3 3 #include "../cqtdata.h" 4 4 #include "../fftdata.h" 5 + #include "fft.h" 5 6 #include "kiss_fftr.h" 6 7 #include <math.h> 7 8 #include <string.h> 9 + #include <stdbool.h> 10 + #include <stdio.h> 11 + 12 + #define CQT_DEBUG 8 13 9 14 // FFT configuration for CQT 10 15 static kiss_fftr_cfg cqtFftCfg = NULL; ··· 53 58 return false; 54 59 } 55 60 61 + // Debug: Print first few center frequencies and expected FFT bins 62 + #ifdef CQT_DEBUG 63 + float centerFreqs[CQT_BINS]; 64 + CQT_GenerateCenterFrequencies(centerFreqs, CQT_BINS, CQT_MIN_FREQ, CQT_MAX_FREQ); 65 + printf("CQT: First 10 center frequencies:\n"); 66 + for (int i = 0; i < 10 && i < CQT_BINS; i++) 67 + { 68 + // FFT bin = freq * fftSize / sampleRate 69 + int expectedBin = (int)(centerFreqs[i] * CQT_FFT_SIZE / 44100.0f); 70 + printf(" Bin %d: %.2f Hz -> FFT bin %d\n", i, centerFreqs[i], expectedBin); 71 + } 72 + 73 + // Also print expected bins for test frequencies 74 + printf("\nCQT: Expected bins for test frequencies:\n"); 75 + float testFreqs[] = {110, 220, 440, 880}; 76 + for (int i = 0; i < 4; i++) 77 + { 78 + int cqtBin = (int)(12 * log(testFreqs[i] / 20.0) / log(2.0) + 0.5); 79 + int fftBin = (int)(testFreqs[i] * CQT_FFT_SIZE / 44100.0f); 80 + printf(" %.0f Hz -> CQT bin %d, FFT bin %d\n", testFreqs[i], cqtBin, fftBin); 81 + } 82 + #endif 83 + 56 84 return true; 57 85 } 58 86 ··· 66 94 for (int bin = 0; bin < CQT_BINS; bin++) 67 95 { 68 96 CqtKernel* kernel = &cqtKernels[bin]; 97 + 98 + // Check if kernel is valid 99 + if (!kernel->real || !kernel->imag || !kernel->indices || kernel->length == 0) 100 + { 101 + cqtData[bin] = 0.0f; 102 + continue; 103 + } 104 + 69 105 float real = 0.0f; 70 106 float imag = 0.0f; 71 107 ··· 73 109 for (int k = 0; k < kernel->length; k++) 74 110 { 75 111 int idx = kernel->indices[k]; 112 + // Ensure index is within bounds 113 + if (idx < 0 || idx > CQT_FFT_SIZE/2) 114 + continue; 115 + 76 116 // Complex multiplication: (a + bi) * (c + di) = (ac - bd) + (ad + bc)i 77 117 real += fftReal[idx] * kernel->real[k] - fftImag[idx] * kernel->imag[k]; 78 118 imag += fftReal[idx] * kernel->imag[k] + fftImag[idx] * kernel->real[k]; 79 119 } 80 120 81 - // Calculate magnitude 82 - cqtData[bin] = sqrt(real * real + imag * imag); 121 + // Calculate magnitude with gain boost 122 + cqtData[bin] = sqrt(real * real + imag * imag) * 4.0f; // Increased gain boost 123 + 124 + // Check for NaN or Inf 125 + if (!isfinite(cqtData[bin])) 126 + cqtData[bin] = 0.0f; 127 + } 128 + } 129 + 130 + // Process CQT from audio data 131 + void CQT_ProcessAudio(void) 132 + { 133 + if (!cqtFftCfg || !cqtEnabled) return; 134 + 135 + // Check if kernels are initialized 136 + bool kernelsValid = false; 137 + for (int i = 0; i < CQT_BINS; i++) 138 + { 139 + if (cqtKernels[i].real && cqtKernels[i].length > 0) 140 + { 141 + kernelsValid = true; 142 + break; 143 + } 144 + } 145 + 146 + if (!kernelsValid) 147 + { 148 + // Kernels not initialized, set all output to zero 149 + memset(cqtData, 0, sizeof(cqtData)); 150 + memset(cqtSmoothingData, 0, sizeof(cqtSmoothingData)); 151 + memset(cqtNormalizedData, 0, sizeof(cqtNormalizedData)); 152 + return; 153 + } 154 + 155 + // Copy audio data from the shared buffer 156 + // TEMPORARY: sampleBuf now has FFT_SIZE * 2 = 2048 * 2 = 4096 samples 157 + memcpy(cqtAudioBuffer, sampleBuf, CQT_FFT_SIZE * sizeof(float)); 158 + 159 + // Check if we have any audio data 160 + float audioSum = 0.0f; 161 + for (int i = 0; i < CQT_FFT_SIZE; i++) 162 + { 163 + audioSum += fabs(cqtAudioBuffer[i]); 164 + } 165 + 166 + if (audioSum < 0.0001f) 167 + { 168 + // No audio data, set output to zero 169 + memset(cqtData, 0, sizeof(cqtData)); 170 + memset(cqtSmoothingData, 0, sizeof(cqtSmoothingData)); 171 + memset(cqtNormalizedData, 0, sizeof(cqtNormalizedData)); 172 + return; 173 + } 174 + 175 + // Perform 4096-point FFT 176 + kiss_fftr(cqtFftCfg, cqtAudioBuffer, cqtFftOutput); 177 + 178 + // Extract real and imaginary components for kernel application 179 + float fftReal[CQT_FFT_SIZE/2 + 1]; 180 + float fftImag[CQT_FFT_SIZE/2 + 1]; 181 + 182 + for (int i = 0; i <= CQT_FFT_SIZE/2; i++) 183 + { 184 + fftReal[i] = cqtFftOutput[i].r; 185 + fftImag[i] = cqtFftOutput[i].i; 186 + } 187 + 188 + // Apply CQT kernels 189 + CQT_ApplyKernels(fftReal, fftImag); 190 + 191 + #ifdef CQT_DEBUG 192 + // Reduced debug output - CQT is working correctly now 193 + static int debugCounter = 0; 194 + if (++debugCounter % 300 == 0) // Print once every 5 seconds 195 + { 196 + // Find peak CQT bin 197 + int peakBin = 0; 198 + float peakVal = 0.0f; 199 + for (int i = 0; i < CQT_BINS; i++) 200 + { 201 + if (cqtData[i] > peakVal) 202 + { 203 + peakVal = cqtData[i]; 204 + peakBin = i; 205 + } 206 + } 207 + 208 + if (peakVal > 1.0f) 209 + { 210 + float peakFreq = CQT_MIN_FREQ * pow(2.0f, peakBin / 12.0f); 211 + printf("CQT: Peak at bin %d (%.1f Hz) with magnitude %.1f\n", 212 + peakBin, peakFreq, peakVal); 213 + } 214 + } 215 + #endif 216 + 217 + // Apply smoothing 218 + for (int i = 0; i < CQT_BINS; i++) 219 + { 220 + cqtSmoothingData[i] = cqtSmoothingData[i] * CQT_SMOOTHING_FACTOR + 221 + cqtData[i] * (1.0f - CQT_SMOOTHING_FACTOR); 222 + } 223 + 224 + // Find peak for normalization 225 + float currentPeak = 0.0f; 226 + for (int i = 0; i < CQT_BINS; i++) 227 + { 228 + if (cqtSmoothingData[i] > currentPeak) 229 + currentPeak = cqtSmoothingData[i]; 230 + } 231 + 232 + // Initialize peak value if needed 233 + if (cqtPeakSmoothValue <= 0.0f) 234 + cqtPeakSmoothValue = 0.1f; 235 + 236 + // Smooth peak value 237 + if (currentPeak > cqtPeakSmoothValue) 238 + cqtPeakSmoothValue = currentPeak; 239 + else 240 + cqtPeakSmoothValue = cqtPeakSmoothValue * 0.99f + currentPeak * 0.01f; 241 + 242 + // Ensure peak value doesn't go too low 243 + if (cqtPeakSmoothValue < 0.0001f) 244 + cqtPeakSmoothValue = 0.0001f; 245 + 246 + // Normalize data 247 + float normalizer = 1.0f / cqtPeakSmoothValue; 248 + for (int i = 0; i < CQT_BINS; i++) 249 + { 250 + cqtNormalizedData[i] = cqtSmoothingData[i] * normalizer; 251 + if (cqtNormalizedData[i] > 1.0f) 252 + cqtNormalizedData[i] = 1.0f; 253 + 254 + // Final NaN check 255 + if (!isfinite(cqtNormalizedData[i])) 256 + cqtNormalizedData[i] = 0.0f; 83 257 } 84 258 } 85 259 86 260 // Process CQT from audio data (using existing FFT data from fftdata.h) 261 + // This is kept for backward compatibility, but not used 87 262 void CQT_Process(const float* fftReal, const float* fftImag) 88 263 { 89 264 if (!cqtFftCfg || !cqtEnabled) return; 90 265 91 - // Note: In the full implementation, we would: 92 - // 1. Get audio data from the shared buffer 93 - // 2. Perform our own 4096-point FFT 94 - // For now, we'll process using provided FFT data 95 - 96 266 // Apply CQT kernels 97 267 CQT_ApplyKernels(fftReal, fftImag); 98 268 ··· 111 281 currentPeak = cqtSmoothingData[i]; 112 282 } 113 283 284 + // Initialize peak value if needed 285 + if (cqtPeakSmoothValue <= 0.0f) 286 + cqtPeakSmoothValue = 0.1f; 287 + 114 288 // Smooth peak value 115 289 if (currentPeak > cqtPeakSmoothValue) 116 290 cqtPeakSmoothValue = currentPeak; 117 291 else 118 292 cqtPeakSmoothValue = cqtPeakSmoothValue * 0.99f + currentPeak * 0.01f; 119 293 294 + // Ensure peak value doesn't go too low 295 + if (cqtPeakSmoothValue < 0.0001f) 296 + cqtPeakSmoothValue = 0.0001f; 297 + 120 298 // Normalize data 121 - float normalizer = (cqtPeakSmoothValue > 0.0001f) ? (1.0f / cqtPeakSmoothValue) : 1.0f; 299 + float normalizer = 1.0f / cqtPeakSmoothValue; 122 300 for (int i = 0; i < CQT_BINS; i++) 123 301 { 124 302 cqtNormalizedData[i] = cqtSmoothingData[i] * normalizer; 125 - if (cqtNormalizedData[i] > 1.0f) cqtNormalizedData[i] = 1.0f; 303 + if (cqtNormalizedData[i] > 1.0f) 304 + cqtNormalizedData[i] = 1.0f; 305 + 306 + // Final NaN check 307 + if (!isfinite(cqtNormalizedData[i])) 308 + cqtNormalizedData[i] = 0.0f; 126 309 } 127 310 } 128 311
+4 -1
src/ext/cqt.h
··· 6 6 // Returns true on success, false on failure 7 7 bool CQT_Open(void); 8 8 9 - // Process CQT from FFT data 9 + // Process CQT from audio buffer (uses shared audio capture buffer) 10 + void CQT_ProcessAudio(void); 11 + 12 + // Process CQT from FFT data (legacy) 10 13 // fftData: Complex FFT output (size should be CQT_FFT_SIZE/2 + 1) 11 14 void CQT_Process(const float* fftReal, const float* fftImag); 12 15
+61 -15
src/ext/cqt_kernel.c
··· 1 1 #include "cqt_kernel.h" 2 + #include "../cqtdata.h" 2 3 #include <math.h> 3 4 #include <stdlib.h> 4 5 #include <string.h> ··· 8 9 #define M_PI 3.14159265358979323846 9 10 #endif 10 11 11 - // Generate logarithmically spaced center frequencies 12 + // Generate logarithmically spaced center frequencies for musical notes 12 13 void CQT_GenerateCenterFrequencies(float* frequencies, int numBins, float minFreq, float maxFreq) 13 14 { 14 - float logRatio = log(maxFreq / minFreq); 15 + // For musical CQT with 12 bins per octave, we want equal temperament spacing 16 + // Each semitone is a factor of 2^(1/12) ≈ 1.0594631 17 + const float semitone = pow(2.0f, 1.0f / 12.0f); 18 + 15 19 for (int i = 0; i < numBins; i++) 16 20 { 17 - frequencies[i] = minFreq * exp(logRatio * i / (numBins - 1)); 21 + // Calculate frequency for each bin based on semitone spacing 22 + frequencies[i] = minFreq * pow(semitone, i); 23 + } 24 + 25 + // Verify we don't exceed maxFreq 26 + if (frequencies[numBins - 1] > maxFreq) 27 + { 28 + // Scale down if necessary 29 + float scale = maxFreq / frequencies[numBins - 1]; 30 + for (int i = 0; i < numBins; i++) 31 + { 32 + frequencies[i] *= scale; 33 + } 18 34 } 19 35 } 20 36 ··· 63 79 CqtWindowType windowType, 64 80 float sparsityThreshold) 65 81 { 66 - // Calculate window length based on frequency (inverse relationship) 67 - float factor = centerFreq / minFreq; 68 - int windowLength = (int)(fftSize / factor); 69 - if (windowLength < 1) windowLength = 1; 82 + // Calculate window length based on Q factor 83 + // windowLength = Q * sampleRate / centerFreq 84 + // This gives us the proper frequency resolution 85 + float Q = CQT_CalculateQ(CQT_BINS_PER_OCTAVE); 86 + int windowLength = (int)(Q * sampleRate / centerFreq); 87 + 88 + // Ensure window length is reasonable 89 + if (windowLength < 32) windowLength = 32; // Minimum window size 70 90 if (windowLength > fftSize) windowLength = fftSize; 71 91 72 92 // Allocate temporary arrays ··· 82 102 83 103 // Generate window in the center of the kernel 84 104 int windowStart = (fftSize - windowLength) / 2; 85 - float* window = &timeKernel[windowStart]; 105 + 106 + // First generate the window 107 + float* tempWindow = (float*)malloc(windowLength * sizeof(float)); 108 + if (!tempWindow) 109 + { 110 + free(timeKernel); 111 + free(freqKernel); 112 + return false; 113 + } 86 114 87 115 switch (windowType) 88 116 { 89 117 case CQT_WINDOW_HAMMING: 90 - generateHammingWindow(window, windowLength); 118 + generateHammingWindow(tempWindow, windowLength); 91 119 break; 92 120 case CQT_WINDOW_GAUSSIAN: 93 - generateGaussianWindow(window, windowLength); 121 + generateGaussianWindow(tempWindow, windowLength); 94 122 break; 95 123 } 96 124 97 - // Modulate window with complex exponential 98 - for (int i = 0; i < fftSize; i++) 125 + // Apply window and modulate with complex exponential 126 + // Following ESP32 reference: modulate based on full FFT size, not window size 127 + for (int i = 0; i < windowLength; i++) 99 128 { 100 - float phase = 2.0f * M_PI * centerFreq / sampleRate * (i - fftSize / 2); 101 - timeKernel[i] *= cos(phase); 129 + int idx = windowStart + i; 130 + // Key insight: use idx (position in full FFT buffer) not i (position in window) 131 + // and center around N/2 where N is the full FFT size 132 + float phase = 2.0f * M_PI * (centerFreq / sampleRate) * (idx - fftSize/2); 133 + timeKernel[idx] = tempWindow[i] * cos(phase); 102 134 } 103 135 104 - // Normalize by window length 136 + // Normalize by window length before FFT (like ESP32) 105 137 for (int i = 0; i < fftSize; i++) 106 138 { 107 139 timeKernel[i] /= windowLength; 108 140 } 141 + 142 + free(tempWindow); 109 143 110 144 // Perform FFT 111 145 kiss_fftr(fftCfg, timeKernel, freqKernel); ··· 140 174 141 175 // Store non-zero elements 142 176 int sparseIndex = 0; 177 + int minIdx = fftSize, maxIdx = 0; // Track range for debug 143 178 for (int i = 0; i <= fftSize/2; i++) 144 179 { 145 180 float magnitude = sqrt(freqKernel[i].r * freqKernel[i].r + ··· 149 184 kernel->real[sparseIndex] = freqKernel[i].r; 150 185 kernel->imag[sparseIndex] = freqKernel[i].i; 151 186 kernel->indices[sparseIndex] = i; 187 + if (i < minIdx) minIdx = i; 188 + if (i > maxIdx) maxIdx = i; 152 189 sparseIndex++; 153 190 } 154 191 } 192 + 193 + #ifdef CQT_DEBUG 194 + // Debug output for specific frequencies 195 + if (fabs(centerFreq - 110.0f) < 1.0f || fabs(centerFreq - 440.0f) < 1.0f) 196 + { 197 + printf("Kernel for %.1f Hz: FFT bins %d-%d (count: %d)\n", 198 + centerFreq, minIdx, maxIdx, nonZeroCount); 199 + } 200 + #endif 155 201 156 202 free(timeKernel); 157 203 free(freqKernel);
+2
src/ext/fft.c
··· 186 186 187 187 memset(sampleBuf, 0, sizeof(float) * FFT_SIZE * 2); 188 188 189 + // TEMPORARY: Using 4096-point FFT to support CQT 190 + // TODO: Restore to 2048 and implement separate buffer for CQT 189 191 fftcfg = kiss_fftr_alloc(FFT_SIZE * 2, false, NULL, NULL); 190 192 191 193 ma_context_config context_config = ma_context_config_init();
+3
src/ext/fft.h
··· 8 8 void FFT_GetFFT(float* _samples); 9 9 void FFT_Close(); 10 10 11 + // CQT needs access to the raw audio buffer 12 + extern float sampleBuf[]; 13 + 11 14 //////////////////////////////////////////////////////////////////////////
+4 -1
src/fftdata.h
··· 1 1 #pragma once 2 2 #include <stdbool.h> 3 - #define FFT_SIZE 1024 3 + // TEMPORARY: Changed from 1024 to 2048 to support CQT's 4096-point FFT 4 + // This breaks FFT bin resolution but enables CQT to work properly 5 + // TODO: Restore to 1024 and implement separate buffer for CQT 6 + #define FFT_SIZE 2048 4 7 extern float fPeakMinValue; 5 8 extern float fPeakSmoothing; 6 9 extern float fPeakSmoothValue;