| 9 | namespace audioproc { |
| 10 | |
| 11 | void rfft_batch( |
| 12 | const float* frames, |
| 13 | float* out_complex, |
| 14 | int num_frames, |
| 15 | int frame_length, |
| 16 | int fft_length) |
| 17 | { |
| 18 | const int n_bins = fft_length / 2 + 1; |
| 19 | |
| 20 | // Allocate FFTW buffers |
| 21 | float* fft_in = (float*)fftwf_malloc(fft_length * sizeof(float)); |
| 22 | fftwf_complex* fft_out = (fftwf_complex*)fftwf_malloc(n_bins * sizeof(fftwf_complex)); |
| 23 | |
| 24 | // Create plan (FFTW_ESTIMATE for fast planning) |
| 25 | fftwf_plan plan = fftwf_plan_dft_r2c_1d(fft_length, fft_in, fft_out, FFTW_ESTIMATE); |
| 26 | |
| 27 | for (int f = 0; f < num_frames; ++f) { |
| 28 | // Copy frame data |
| 29 | std::memcpy(fft_in, frames + f * frame_length, frame_length * sizeof(float)); |
| 30 | // Zero-pad if fft_length > frame_length |
| 31 | if (fft_length > frame_length) { |
| 32 | std::memset(fft_in + frame_length, 0, (fft_length - frame_length) * sizeof(float)); |
| 33 | } |
| 34 | |
| 35 | fftwf_execute(plan); |
| 36 | |
| 37 | // Copy interleaved (re, im) output |
| 38 | float* dst = out_complex + f * n_bins * 2; |
| 39 | for (int k = 0; k < n_bins; ++k) { |
| 40 | dst[2 * k] = fft_out[k][0]; // real |
| 41 | dst[2 * k + 1] = fft_out[k][1]; // imag |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | fftwf_destroy_plan(plan); |
| 46 | fftwf_free(fft_in); |
| 47 | fftwf_free(fft_out); |
| 48 | } |
| 49 | |
| 50 | void rfft_magnitude_batch( |
| 51 | const float* frames, |
no outgoing calls
no test coverage detected