static void create_filter(struct eq_data *eq, unsigned size_log2, struct eq_gain *gains, unsigned num_gains, double beta) { int i; int half_block_size = eq->block_size >> 1; double window_mod = 1.0 / kaiser_window(0.0, beta); fft_t *fft = fft_new(size_log2); float *time_filter = (float*)calloc(eq->block_size * 2, sizeof(*time_filter)); if (!fft || !time_filter) goto end; // Make sure bands are in correct order. qsort(gains, num_gains, sizeof(*gains), gains_cmp); // Compute desired filter response. generate_response(eq->filter, gains, num_gains, half_block_size); // Get equivalent time-domain filter. fft_process_inverse(fft, time_filter, eq->filter, 1); // ifftshift() to create the correct linear phase filter. // The filter response was designed with zero phase, which won't work unless we compensate // for the repeating property of the FFT here by flipping left and right blocks. for (i = 0; i < half_block_size; i++) { float tmp = time_filter[i + half_block_size]; time_filter[i + half_block_size] = time_filter[i]; time_filter[i] = tmp; } // Apply a window to smooth out the frequency repsonse. for (i = 0; i < (int)eq->block_size; i++) { // Kaiser window. double phase = (double)i / (eq->block_size - 1); phase = 2.0 * (phase - 0.5); time_filter[i] *= window_mod * kaiser_window(phase, beta); } // Debugging. #if 0 FILE *file = fopen("/tmp/test.txt", "w"); if (file) { for (i = 0; i < (int)eq->block_size; i++) fprintf(file, "%.6f\n", time_filter[i]); fclose(file); } #endif // Padded FFT to create our FFT filter. fft_process_forward(eq->fft, eq->filter, time_filter, 1); end: fft_free(fft); free(time_filter); }
static void eq_process(void *data, struct dspfilter_output *output, const struct dspfilter_input *input) { float *out; const float *in; unsigned input_frames; struct eq_data *eq = (struct eq_data*)data; output->samples = eq->buffer; output->frames = 0; out = eq->buffer; in = input->samples; input_frames = input->frames; while (input_frames) { unsigned write_avail = eq->block_size - eq->block_ptr; if (input_frames < write_avail) write_avail = input_frames; memcpy(eq->block + eq->block_ptr * 2, in, write_avail * 2 * sizeof(float)); in += write_avail * 2; input_frames -= write_avail; eq->block_ptr += write_avail; // Convolve a new block. if (eq->block_ptr == eq->block_size) { unsigned i, c; for (c = 0; c < 2; c++) { fft_process_forward(eq->fft, eq->fftblock, eq->block + c, 2); for (i = 0; i < 2 * eq->block_size; i++) eq->fftblock[i] = fft_complex_mul(eq->fftblock[i], eq->filter[i]); fft_process_inverse(eq->fft, out + c, eq->fftblock, 2); } // Overlap add method, so add in saved block now. for (i = 0; i < 2 * eq->block_size; i++) out[i] += eq->save[i]; // Save block for later. memcpy(eq->save, out + 2 * eq->block_size, 2 * eq->block_size * sizeof(float)); out += eq->block_size * 2; output->frames += eq->block_size; eq->block_ptr = 0; } } }
static void create_filter(struct eq_data *eq, unsigned size_log2, struct eq_gain *gains, unsigned num_gains, double beta, const char *filter_path) { int i; int half_block_size = eq->block_size >> 1; double window_mod = 1.0 / kaiser_window_function(0.0, beta); fft_t *fft = fft_new(size_log2); float *time_filter = (float*)calloc(eq->block_size * 2 + 1, sizeof(*time_filter)); if (!fft || !time_filter) goto end; /* Make sure bands are in correct order. */ qsort(gains, num_gains, sizeof(*gains), gains_cmp); /* Compute desired filter response. */ generate_response(eq->filter, gains, num_gains, half_block_size); /* Get equivalent time-domain filter. */ fft_process_inverse(fft, time_filter, eq->filter, 1); // ifftshift() to create the correct linear phase filter. // The filter response was designed with zero phase, which won't work unless we compensate // for the repeating property of the FFT here by flipping left and right blocks. for (i = 0; i < half_block_size; i++) { float tmp = time_filter[i + half_block_size]; time_filter[i + half_block_size] = time_filter[i]; time_filter[i] = tmp; } /* Apply a window to smooth out the frequency repsonse. */ for (i = 0; i < (int)eq->block_size; i++) { /* Kaiser window. */ double phase = (double)i / eq->block_size; phase = 2.0 * (phase - 0.5); time_filter[i] *= window_mod * kaiser_window_function(phase, beta); } /* Debugging. */ if (filter_path) { FILE *file = fopen(filter_path, "w"); if (file) { for (i = 0; i < (int)eq->block_size - 1; i++) fprintf(file, "%.8f\n", time_filter[i + 1]); fclose(file); } } /* Padded FFT to create our FFT filter. * Make our even-length filter odd by discarding the first coefficient. * For some interesting reason, this allows us to design an odd-length linear phase filter. */ fft_process_forward(eq->fft, eq->filter, time_filter + 1, 1); end: fft_free(fft); free(time_filter); }