Generate a sample with spectral leakage: a bass tone near the mid band boundary (3500 Hz — just below the 3688 Hz boundary) plus actual mid content plus noise. The 512-sample audio::fft::FFT window causes the 3500 Hz tone to leak significant energy into the mid bin.
| 85 | // content plus noise. The 512-sample audio::fft::FFT window causes the 3500 Hz tone |
| 86 | // to leak significant energy into the mid bin. |
| 87 | audio::Sample makeMixWithLeakage(float bassAmp, float leakageBassAmp, |
| 88 | float midAmp, float trebAmp, |
| 89 | float noiseAmp, u32 timestamp, |
| 90 | int count = 512, |
| 91 | float sampleRate = 44100.0f) { |
| 92 | vector<i16> data(count, 0); |
| 93 | |
| 94 | // Normal bass (200 Hz) |
| 95 | for (int i = 0; i < count; ++i) { |
| 96 | float phase = 2.0f * FL_M_PI * 200.0f * i / sampleRate; |
| 97 | data[i] = clampI16(static_cast<float>(data[i]) + |
| 98 | bassAmp * fl::sinf(phase)); |
| 99 | } |
| 100 | |
| 101 | // Leakage bass: 3500 Hz — nominally in bass band (20-3688 Hz) but |
| 102 | // audio::fft::FFT spectral leakage bleeds energy into the mid bin (3688-7356 Hz). |
| 103 | // A 512-sample Hann window at 44100 Hz has main-lobe width ≈ 172 Hz, |
| 104 | // so 3500 Hz is only 188 Hz from the 3688 Hz boundary — well within |
| 105 | // the leakage zone. With rectangular window (which kiss_fft uses), |
| 106 | // sidelobes are even worse. |
| 107 | for (int i = 0; i < count; ++i) { |
| 108 | float phase = 2.0f * FL_M_PI * 3500.0f * i / sampleRate; |
| 109 | data[i] = clampI16(static_cast<float>(data[i]) + |
| 110 | leakageBassAmp * fl::sinf(phase)); |
| 111 | } |
| 112 | |
| 113 | // Actual mid content (5000 Hz) |
| 114 | for (int i = 0; i < count; ++i) { |
| 115 | float phase = 2.0f * FL_M_PI * 5000.0f * i / sampleRate; |
| 116 | data[i] = clampI16(static_cast<float>(data[i]) + |
| 117 | midAmp * fl::sinf(phase)); |
| 118 | } |
| 119 | |
| 120 | // Treble (9000 Hz) |
| 121 | for (int i = 0; i < count; ++i) { |
| 122 | float phase = 2.0f * FL_M_PI * 9000.0f * i / sampleRate; |
| 123 | data[i] = clampI16(static_cast<float>(data[i]) + |
| 124 | trebAmp * fl::sinf(phase)); |
| 125 | } |
| 126 | |
| 127 | // Broadband noise |
| 128 | fl_random rng(static_cast<u16>(timestamp * 7 + 31)); |
| 129 | for (int i = 0; i < count; ++i) { |
| 130 | float noise = (static_cast<float>(rng.random16()) / 32767.5f) - 1.0f; |
| 131 | data[i] = clampI16(static_cast<float>(data[i]) + noiseAmp * noise); |
| 132 | } |
| 133 | return audio::Sample(data, timestamp); |
| 134 | } |
| 135 | |
| 136 | } // namespace |
| 137 |
no test coverage detected