35 #include <boost/format.hpp> 37 static unsigned int ipow(
unsigned int x,
unsigned int y)
43 for(i = 0; i < y; i++) {
52 unsigned int filter_length,
54 unsigned int inout_buffer_length,
56 unsigned int suggested_transform_length)
61 M = inout_buffer_length;
63 if((cascade != NULL) && (cascade->M !=
M)) cascade = NULL;
66 std::cerr <<
"Warning -- OSFilter asked to implement a long filter against a short buffer." << std::endl;
70 if(suggested_transform_length > (
M +
Q - 1)) {
71 N = suggested_transform_length;
83 std::complex<float> * filter_in = (std::complex<float> *) fftwf_malloc(
sizeof(std::complex<float>) *
N);
84 filter_fft = (std::complex<float> *) fftwf_malloc(
sizeof(std::complex<float>) *
N);
87 fftwf_plan tplan = fftwf_plan_dft_1d(
N, (fftwf_complex*) filter_in, (fftwf_complex*)
filter_fft,
88 FFTW_FORWARD, FFTW_ESTIMATE);
93 for(i = 0; i < N; i++) filter_in[i] = std::complex<float>(0.0,0.0);
95 float gain_corr = 1.0 / ((float)
N) * filter_gain;
96 for(i = 0; i < filter_length; i++) filter_in[i] = std::complex<float>(filter_impulse_response[i] * gain_corr, 0.0);
102 fftwf_destroy_plan(tplan);
105 if((cascade != NULL) && (cascade->N !=
N)) cascade = NULL;
108 if(cascade != NULL) {
109 for(i = 0; i <
N; i++) {
110 std::complex<double> a = filter_fft[i];
111 std::complex<double> b = cascade->filter_fft[i];
112 std::complex<double> ff = a * b * ((double) N);
113 filter_fft[i] = std::complex<float>(ff.real(), ff.imag());
125 float high_pass_edge,
128 unsigned int filter_length,
132 unsigned int inout_buffer_length,
133 unsigned int suggested_transform_length)
141 M = inout_buffer_length;
143 std::cerr <<
"Warning -- OSFilter asked to implement a long filter against a short buffer." << std::endl;
147 if(suggested_transform_length > (
M +
Q - 1)) {
148 N = suggested_transform_length;
161 std::complex<float> * filter_in = (std::complex<float> *) fftwf_malloc(
sizeof(std::complex<float>) *
N);
162 filter_fft = (std::complex<float> *) fftwf_malloc(
sizeof(std::complex<float>) *
N);
165 for(i = 0; i < N; i++) filter_in[i] = std::complex<float>(0.0,0.0);
166 filter_in[
Q/2] = std::complex<float>(1.0, 0.0);
169 fftwf_plan fplan = fftwf_plan_dft_1d(
N, (fftwf_complex *) filter_in, (fftwf_complex *)
filter_fft,
170 FFTW_FORWARD, FFTW_ESTIMATE);
171 fftwf_plan ifplan = fftwf_plan_dft_1d(
N, (fftwf_complex *) filter_fft, (fftwf_complex *) filter_in,
172 FFTW_BACKWARD, FFTW_ESTIMATE);
175 fftwf_execute(fplan);
177 float freq_step = sample_rate / ((float)
N);
180 for(fr = 0.0, i = 0, j = (
N - 1); i <
N/2; i++, j--, fr += freq_step) {
181 if(fr < low_cutoff) {
182 filter_fft[i] = std::complex<float>(0.0,0.0);
183 filter_fft[j] = std::complex<float>(0.0,0.0);
185 else if(fr < low_pass_edge) {
186 float mult = (fr - low_cutoff) / (low_pass_edge - low_cutoff);
187 filter_fft[i] = filter_fft[i] * std::complex<float>(mult, 0.0);
188 filter_fft[j] = filter_fft[j] * std::complex<float>(mult, 0.0);
190 else if(fr < high_pass_edge) {
193 else if(fr < high_cutoff) {
194 float mult = 1.0 - ((fr - high_pass_edge) / (high_cutoff - high_pass_edge));
195 filter_fft[i] = filter_fft[i] * std::complex<float>(mult, 0.0);
196 filter_fft[j] = filter_fft[j] * std::complex<float>(mult, 0.0);
199 filter_fft[i] = std::complex<float>(0.0,0.0);
200 filter_fft[j] = std::complex<float>(0.0,0.0);
205 fftwf_execute(ifplan);
208 for(i = 0; i <
Q/2; i++) {
210 float ang = 2.0 * M_PI * ((float) ii) / ((float)
Q);
211 std::complex<float> wf(0.5 + 0.5 * cos(ang), 0.0);
212 filter_in[i] = filter_in[i] * wf;
213 filter_in[
Q - i] = filter_in[
Q - i] * wf;
215 for(i =
Q; i <
N; i++) {
216 filter_in[i] = std::complex<float>(0.0, 0.0);
220 fftwf_execute(fplan);
224 for(i = 0; i <
N; i++) {
225 float v = abs(filter_fft[i]);
226 if(v > maxval) maxval = v;
229 std::complex<float> normalize(filter_gain / (((
float) N) * maxval), 0.0);
231 for(i = 0; i <
N; i++) {
232 filter_fft[i] = filter_fft[i] * normalize;
236 fftwf_destroy_plan(fplan);
237 fftwf_destroy_plan(ifplan);
240 fftwf_free(filter_in);
254 unsigned int N_guess, N_best, E_best;
258 for(i = 1; i <= 0xff; i++) {
259 unsigned int a = i & 0xf;
260 unsigned int b = (i >> 4) & 0x3;
261 unsigned int c = (i >> 6) & 0x3;
263 if(N_guess >= (
M +
Q - 1)) {
264 unsigned slop = N_guess - (
M +
Q - 1);
279 fft_input = (std::complex<float> *) fftwf_malloc(
sizeof(std::complex<float>) *
N);
280 fft_output = (std::complex<float> *) fftwf_malloc(
sizeof(std::complex<float>) *
N);
281 ifft_output = (std::complex<float> *) fftwf_malloc(
sizeof(std::complex<float>) *
N);
287 FFTW_FORWARD, FFTW_ESTIMATE);
289 (fftwf_complex *) fft_output,
291 FFTW_BACKWARD, FFTW_ESTIMATE);
294 for(i = 0; i <
Q-1; i++) fft_input[i] = std::complex<float>(0.0,0.0);
302 for(i = 0, j =
Q-1; i < (
M * instride); i += instride, j++) {
303 fft_input[j] = std::complex<float>(inbuf[i], 0.0);
312 for(i = (
tail_index * instride), j = 0; j <
Q-1; i += instride, j++) {
313 fft_input[j] = std::complex<float>(inbuf[i], 0.0);
317 for(i = 0; i <
N; i++) {
327 for(i = 0, j = Q-1; i < (
M * outstride); i += outstride, j++) {
338 memcpy(&(
fft_input[
Q-1]), inbuf,
sizeof(std::complex<float>) *
M);
350 for(i = 0; i <
N; i++) {
359 memcpy(outbuf, &(
ifft_output[
Q-1]),
sizeof(std::complex<float>) * M);
367 os <<
"# idx real imag abs arg" << std::endl;
368 for(i = 0; i <
N; i++) {
371 os << i <<
" " <<
filter_fft[i].real() <<
" " <<
filter_fft[i].imag() <<
" " << mag <<
" " << phase << std::endl;
This is an overlap-and-save frequency domain implementation of a general FIR filter widget...
int guessN()
pick a likely N - FFT length.
static unsigned int ipow(unsigned int x, unsigned int y)
double low_edge
parameters that we keep to support display masks on the spectrogram
std::complex< float > * fft_input
a copy of the input stream.
fftwf_plan backward_plan
plans for fftw transform ops
void dump(std::ostream &os)
dump the filter FFT to the output stream
std::complex< float > * ifft_output
the output stream + overlap discard
OSFilter(float low_cutoff, float low_pass_edge, float high_pass_edge, float high_cutoff, unsigned int filter_length, float filter_gain, float sample_rate, unsigned int inout_buffer_length, unsigned int suggested_transform_length=0)
constructor
unsigned int tail_index
the beginning of the end.
std::complex< float > * filter_fft
FFT image of the input filter.
unsigned int apply(std::complex< float > *inbuf, std::complex< float > *outbuf, float outgain=1.0)
run the filter on a complex input stream
std::complex< float > * fft_output
the transformed input stream + overlap
unsigned int N
the total length of the transform N > (M + Q-1)
unsigned int M
the input buffer length;
unsigned int Q
the filter length