Generate a synthetic kick drum: 60Hz body + 120Hz harmonic (30ms decay) + click transient The click uses multiple high-frequency sines sustained long enough for CQ FFT to resolve
| 357 | /// Generate a synthetic kick drum: 60Hz body + 120Hz harmonic (30ms decay) + click transient |
| 358 | /// The click uses multiple high-frequency sines sustained long enough for CQ FFT to resolve |
| 359 | inline Sample makeKickDrum(fl::u32 timestamp, float amplitude = 16000.0f, |
| 360 | int count = 512, float sampleRate = 44100.0f) { |
| 361 | fl::vector<fl::i16> data(count, 0); |
| 362 | for (int i = 0; i < count; ++i) { |
| 363 | float t = static_cast<float>(i) / sampleRate; |
| 364 | // Body: 60Hz fundamental with 30ms exponential decay |
| 365 | float bodyDecay = fl::expf(-t / 0.030f); |
| 366 | float body = amplitude * 0.7f * bodyDecay * fl::sinf(2.0f * FL_M_PI * 60.0f * t); |
| 367 | // Second harmonic: 120Hz |
| 368 | float harm2 = amplitude * 0.3f * bodyDecay * fl::sinf(2.0f * FL_M_PI * 120.0f * t); |
| 369 | // Click transient: sustained for ~200 samples with fast exponential decay |
| 370 | // Uses multiple frequencies in the CQ treble range (bins 10-12) |
| 371 | float clickDecay = fl::expf(-t / 0.003f); // ~3ms decay, covers ~130 samples |
| 372 | float click = amplitude * 0.8f * clickDecay * ( |
| 373 | 0.5f * fl::sinf(2.0f * FL_M_PI * 2000.0f * t) + |
| 374 | 0.3f * fl::sinf(2.0f * FL_M_PI * 3000.0f * t) + |
| 375 | 0.2f * fl::sinf(2.0f * FL_M_PI * 4000.0f * t) |
| 376 | ); |
| 377 | float sample = body + harm2 + click; |
| 378 | if (sample > 32767.0f) sample = 32767.0f; |
| 379 | if (sample < -32768.0f) sample = -32768.0f; |
| 380 | data[i] = static_cast<fl::i16>(sample); |
| 381 | } |
| 382 | return Sample(data, timestamp); |
| 383 | } |
| 384 | |
| 385 | /// Generate a synthetic snare: 250Hz body (25ms decay) + high-frequency noise (50ms decay) |
| 386 | /// Produces moderate bass + significant treble energy from noise rattles |
no test coverage detected