SAF
Loading...
Searching...
No Matches
saf_utility_filters.c
Go to the documentation of this file.
1/*
2 * Copyright 2019 Leo McCormack
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
27#include "saf_utilities.h"
28#include "saf_externals.h"
29
35(
37 int winlength,
38 float* x
39)
40{
41 int i, N;
42
43 /* if winlength is odd -> symmetric window (mid index has value=1) */
44 if ( !(winlength % 2 == 0) )
45 N = winlength-1;
46 /* otherwise, if winlength is even (index: winlength/2+1 = 1.0, but first
47 * value != last value) */
48 else
49 N = winlength;
50
51 switch(type){
53 break;
54
56 for(i=0; i<winlength; i++)
57 x[i] *= 0.54f - 0.46f * (cosf(2.0f*SAF_PI*(float)i/(float)N)); /* more wide-spread coefficient values */
58 /* optimal equiripple coefficient values: */
59 /*x[i] *= 0.53836f - 0.46164f * (cosf(2.0f*SAF_PI*(float)i/(float)N));*/
60 break;
61
63 for(i=0; i<winlength; i++)
64 x[i] *= 0.5f - 0.5f * (cosf(2.0f*SAF_PI*(float)i/(float)N));
65 break;
66
68 for(i=0; i<winlength; i++)
69 x[i] *= 1.0f - 2.0f * fabsf((float)i-((float)N/2.0f))/(float)N;
70 break;
71
73 for(i=0; i<winlength; i++){
74 x[i] *= 0.42659f -
75 0.49656f *cosf(2.0f*SAF_PI*(float)i/(float)N) +
76 0.076849f*cosf(4.0f*SAF_PI*(float)i/(float)N);
77 }
78 break;
79
81 for(i=0; i<winlength; i++){
82 x[i] *= 0.355768f -
83 0.487396f*cosf(2.0f*SAF_PI*(float)i/(float)N) +
84 0.144232f*cosf(4.0f*SAF_PI*(float)i/(float)N) -
85 0.012604f*cosf(6.0f*SAF_PI*(float)i/(float)N);
86 }
87 break;
88
90 for(i=0; i<winlength; i++){
91 x[i] *= 0.3635819f -
92 0.4891775f*cosf(2.0f*SAF_PI*(float)i/(float)N) +
93 0.1365995f*cosf(4.0f*SAF_PI*(float)i/(float)N) +
94 0.0106411f*cosf(4.0f*SAF_PI*(float)i/(float)N);
95 }
96 break;
97
99 for(i=0; i<winlength; i++){
100 x[i] *= 0.35875f -
101 0.48829f*cosf(2.0f*SAF_PI*(float)i/(float)N) +
102 0.14128f*cosf(4.0f*SAF_PI*(float)i/(float)N) +
103 0.01168f*cosf(4.0f*SAF_PI*(float)i/(float)N);
104 }
105 break;
106 }
107}
108
111static void applyIIR_1
112(
113 float* in_signal,
114 int nSamples,
115 float* b,
116 float* a,
117 float* wz,
118 float* out_signal
119)
120{
121 int n;
122 float wn;
123
124 /* difference equation (Direct form 2) */
125 for (n=0; n<nSamples; n++){
126 /* numerator */
127 wn = in_signal[n] - (a[1] * wz[0]);
128
129 /* denominator */
130 out_signal[n] = b[0] * wn + b[1] * wz[0];
131
132 /* shuffle delays */
133 wz[0] = wn;
134 }
135}
136
139static void applyIIR_2
140(
141 float* in_signal,
142 int nSamples,
143 float* b,
144 float* a,
145 float* wz,
146 float* out_signal
147)
148{
149 int n;
150 float wn;
151
152 /* Difference equation (Direct form 2) */
153 for (n=0; n<nSamples; n++){
154 /* numerator */
155 wn = in_signal[n] - a[1] * wz[0] - a[2] * wz[1];
156
157 /* denominator */
158 out_signal[n] = b[0] * wn + b[1] * wz[0] + b[2] * wz[1];
159
160 /* shuffle delays */
161 wz[1] = wz[0];
162 wz[0] = wn;
163 }
164}
165
168static void applyIIR_3
169(
170 float* in_signal,
171 int nSamples,
172 float* b,
173 float* a,
174 float* wz,
175 float* out_signal
176)
177{
178 int n;
179 float wn;
180
181 /* Difference equation (Direct form 2) */
182 for (n=0; n<nSamples; n++){
183 /* numerator */
184 wn = in_signal[n] - a[1] * wz[0] - a[2] * wz[1] - a[3] * wz[2];
185
186 /* denominator */
187 out_signal[n] = b[0] * wn + b[1] * wz[0] + b[2] * wz[1] + b[3] * wz[2];
188
189 /* shuffle delays */
190 wz[2] = wz[1];
191 wz[1] = wz[0];
192 wz[0] = wn;
193 }
194}
195
196
197/* ========================================================================== */
198/* Misc. Functions */
199/* ========================================================================== */
200
202(
204 int winlength,
205 float* win
206)
207{
208 int i;
209 for(i=0; i<winlength; i++)
210 win[i] = 1.0f;
211 applyWindowingFunction(type, winlength, win);
212}
213
215(
216 float* centreFreqs,
217 int nCentreFreqs,
218 float* cutoffFreqs
219)
220{
221 int i;
222 for(i=0; i<nCentreFreqs-1; i++)
223 cutoffFreqs[i] = 2.0f*centreFreqs[i]/sqrtf(2.0f);
224}
225
227(
228 float* x,
229 int len
230)
231{
232 int i;
233 float_complex* ctd_tmp, *tdi_f, *tdi_f_labs, *dt_min_f;
234 void* hFFT;
235
236 /* prep */
237 ctd_tmp = malloc1d(len*sizeof(float_complex));
238 tdi_f = malloc1d(len*sizeof(float_complex));
239 tdi_f_labs = malloc1d(len*sizeof(float_complex));
240 dt_min_f = malloc1d(len*sizeof(float_complex));
241 saf_fft_create(&hFFT, len);
242
243 /* fft */
244 for(i=0; i<len; i++)
245 ctd_tmp[i] = cmplxf(x[i], 0.0f);
246 saf_fft_forward(hFFT, (float_complex*)ctd_tmp, (float_complex*)tdi_f);
247
248 /* take log(cabs()) */
249 for(i=0; i<len; i++)
250 tdi_f_labs[i] = cmplxf(logf(cabsf(tdi_f[i])), 0.0f);
251
252 /* Hilbert to acquire discrete-time analytic signal */
253 hilbert(tdi_f_labs, len, dt_min_f);
254
255 /* compute minimum-phase response, and apply to tdi_f to flatten it to unity magnitude */
256 for(i=0; i<len; i++)
257 dt_min_f[i] = ccdivf(tdi_f[i], cexpf(conjf(dt_min_f[i])));
258
259 /* ifft */
260 saf_fft_backward(hFFT, dt_min_f, ctd_tmp);
261
262 /* overwrite input with EQ'd version */
263 for(i=0; i<len; i++)
264 x[i] = crealf(ctd_tmp[i]);
265
266 /* tidy up */
267 saf_fft_destroy(&hFFT);
268 free(ctd_tmp);
269 free(tdi_f);
270 free(tdi_f_labs);
271 free(dt_min_f);
272}
273
275(
276 int inFFTsize,
277 int outFFTsize,
278 int nFilters,
279 float_complex* filters_in,
280 float_complex* filters_out
281)
282{
283 int i, j, nBins_in, nBins_out;
284 float* M_ifft, *M_ifft_fl;
285 float_complex* tmp;
286 void* hFFT_in, *hFFT_out;
287
288 nBins_in = inFFTsize/2 + 1;
289 nBins_out = outFFTsize/2 + 1;
290 saf_rfft_create(&hFFT_in, inFFTsize);
291 saf_rfft_create(&hFFT_out, outFFTsize);
292 M_ifft = calloc1d(SAF_MAX(inFFTsize, outFFTsize), sizeof(float));
293 M_ifft_fl = calloc1d(SAF_MAX(inFFTsize, outFFTsize), sizeof(float));
294 tmp = malloc1d(SAF_MAX(nBins_in, nBins_out) * sizeof(float_complex));
295
296 for(i=0; i<nFilters; i++){
297 for(j=0; j<nBins_in; j++)
298 tmp[j] = filters_in[j*nFilters+i];
299 saf_rfft_backward(hFFT_in, tmp, M_ifft);
300
301 /* flip */
302 for(j=0; j<outFFTsize/2; j++){
303 M_ifft_fl[j] = M_ifft[inFFTsize/2+j];
304 M_ifft_fl[inFFTsize/2+j] = M_ifft[j];
305 }
306 saf_rfft_forward(hFFT_out, M_ifft_fl, tmp);
307 for(j=0; j<nBins_out; j++)
308 filters_out[j*nFilters+i] = tmp[j];
309 }
310
311 saf_rfft_destroy(&hFFT_in);
312 saf_rfft_destroy(&hFFT_out);
313 free(M_ifft);
314 free(M_ifft_fl);
315 free(tmp);
316}
317
319(
320 float BW
321)
322{
323 return sqrtf(powf(2.0f, BW))/(powf(2.0f, BW)-1.0f);
324}
325
327(
328 float Q
329)
330{
331 return logf( (2.0f*Q*Q+1.0f)/(2.0f*Q*Q) + sqrtf( powf((2.0f*Q*Q+1.0f)/(Q*Q+2.23e-13f), 2.0f)/4.0f - 1.0f )) /logf(2.0f);
332}
333
334
335/* ========================================================================== */
336/* IIR Filter Functions */
337/* ========================================================================== */
338
340(
341 BIQUAD_FILTER_TYPES filterType,
342 float fc,
343 float fs,
344 float Q,
345 float gain_dB,
346 float b[3],
347 float a[3]
348)
349{
350 float K, KK, D, V0, A, w0, alpha, a0;
351
352 a[0] = 1.0f;
353
354 /* calculate the IIR filter coefficients */
355 switch (filterType){
357 /* Filter design equations - DAFX (2nd ed) p50 */
358 K = tanf(SAF_PI * fc/fs);
359 KK = K * K;
360 D = KK * Q + K + Q;
361 b[0] = (KK * Q)/D;
362 b[1] = (2.0f * KK * Q)/D;
363 b[2] = b[0];
364 a[1] = (2.0f * Q * (KK - 1.0f))/D;
365 a[2] = (KK * Q - K + Q)/D;
366 break;
367
369 /* Filter design equations - https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html */
370 w0 = 2.0f*SAF_PI*fc/fs;
371 alpha = sinf(w0)/(2.0f*Q);
372 b[0] = (1.0f - cosf(w0))/2.0f;
373 b[1] = 1.0f - cosf(w0);
374 b[2] = b[0];
375 a0 = 1.0f + alpha;
376 a[1] = -2.0f*cosf(w0);
377 a[2] = 1.0f - alpha;
378
379 /* Scale by a0, since applyBiQuadFilter() and applyIIR() assume a0 = 1.0 */
380 b[0] /= a0;
381 b[1] /= a0;
382 b[2] /= a0;
383 a[1] /= a0;
384 a[2] /= a0;
385 break;
386
388 /* Filter design equations - DAFX (2nd ed) p50 */
389 K = tanf(SAF_PI * fc/fs);
390 KK = K * K;
391 D = KK * Q + K + Q;
392 b[0] = (Q)/D;
393 b[1] = -(2.0f * Q)/D;
394 b[2] = b[0];
395 a[1] = (2.0f * Q * (KK - 1.0f))/D;
396 a[2] = (KK * Q - K + Q)/D;
397 break;
398
400 /* Filter design equations - https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html */
401 w0 = 2.0f*SAF_PI*fc/fs;
402 alpha = sinf(w0)/(2.0f*Q);
403 b[0] = (1.0f + cosf(w0))/2.0f;
404 b[1] = -(1.0f + cosf(w0));
405 b[2] = b[0];
406 a0 = 1.0f + alpha;
407 a[1] = -2.0f*cosf(w0);
408 a[2] = 1.0f - alpha;
409
410 /* Scale by a0, since applyBiQuadFilter() and applyIIR() assume a0 = 1.0 */
411 b[0] /= a0;
412 b[1] /= a0;
413 b[2] /= a0;
414 a[1] /= a0;
415 a[2] /= a0;
416 break;
417
419 /* Filter design equations - DAFX (2nd ed) p64 */
420 K = tanf(SAF_PI * fc/fs);
421 V0 = powf(10.0f, (gain_dB/20.0f));
422 if (V0 < 1.0f)
423 V0 = 1.0f/V0;
424 KK = K * K;
425 if (gain_dB > 0.0f){
426 D = 1.0f + sqrtf(2.0f) * K + KK;
427 b[0] = (1.0f + sqrtf(2.0f * V0) * K + V0 * KK)/D;
428 b[1] = (2.0f*(V0*KK - 1.0f))/D;
429 b[2] = (1.0f - sqrtf(2.0f * V0) * K + V0 * KK)/D;
430 a[1] = (2.0f * (KK - 1.0f))/D;
431 a[2] = (1.0f - sqrtf(2.0f) * K + KK)/D;
432 }
433 else{
434 D = V0 + sqrtf(2.0f*V0)*K + KK;
435 b[0] = (V0*(1.0f + sqrtf(2.0f)*K + KK))/D;
436 b[1] = (2.0f*V0*(KK - 1.0f))/D;
437 b[2] = (V0*(1.0f - sqrtf(2.0f)*K + KK))/D;
438 a[1] = (2.0f * (KK - V0))/D;
439 a[2] = (V0 - sqrtf(2.0f*V0)*K + KK)/D;
440 }
441 break;
442
444 /* Filter design equations - https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html */
445 A = powf(10.0f, gain_dB/40.0f);
446 w0 = 2.0f*SAF_PI*fc/fs;
447 alpha = sinf(w0)/(2.0f*Q);
448 b[0] = A*( (A+1.0f) - (A-1.0f) * cosf(w0) + 2.0f*sqrtf(A)*alpha );
449 b[1] = 2.0f*A*( (A-1.0f) - (A+1.0f) * cosf(w0) );
450 b[2] = A*( (A+1.0f) - (A-1.0f) * cosf(w0) - 2.0f*sqrtf(A)*alpha );
451 a0 = (A+1.0f) + (A-1.0f) * cosf(w0) + 2.0f*sqrtf(A)*alpha;
452 a[1] = -2.0f*( (A-1.0f) + (A+1.0f) * cosf(w0) );
453 a[2] = (A+1.0f) + (A-1.0f) * cosf(w0) - 2.0f*sqrtf(A)*alpha;
454
455 /* Scale by a0, since applyBiQuadFilter() and applyIIR() assume a0 = 1.0 */
456 b[0] /= a0;
457 b[1] /= a0;
458 b[2] /= a0;
459 a[1] /= a0;
460 a[2] /= a0;
461 break;
462
464 /* Filter design equations - DAFX (2nd ed) p64 */
465 K = tanf(SAF_PI * fc/fs);
466 V0 = powf(10.0f, (gain_dB/20.0f));
467 if (V0 < 1.0f)
468 V0 = 1.0f/V0;
469 KK = K * K;
470 if (gain_dB > 0.0f){
471 D = 1.0f + sqrtf(2.0f) * K + KK;
472 b[0] = (V0 + sqrtf(2.0f * V0) * K + KK)/D;
473 b[1] = (2.0f*(KK - V0))/D;
474 b[2] = (V0 - sqrtf(2.0f * V0) * K + KK)/D;
475 a[1] = (2.0f*(KK - 1.0f))/D;
476 a[2] = (1.0f - sqrtf(2.0f) * K + KK)/D;
477 }
478 else{
479 D = 1.0f + sqrtf(2.0f*V0) * K + V0*KK;
480 b[0] = (V0*(1.0f + sqrtf(2.0f)*K + KK))/D;
481 b[1] = (2.0f*V0*(KK - 1.0f))/D;
482 b[2] = (V0*(1.0f - sqrtf(2.0f)*K + KK))/D;
483 a[1] = (2.0f * (V0*KK - 1.0f))/D;
484 a[2] = (1.0f - sqrtf(2.0f*V0)*K + V0*KK)/D;
485 }
486 break;
487
489 /* Filter design equations - https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html */
490 A = powf(10.0f, gain_dB/40.0f);
491 w0 = 2.0f*SAF_PI*fc/fs;
492 alpha = sinf(w0)/(2.0f*Q);
493 b[0] = A*( (A+1.0f) + (A-1.0f) * cosf(w0) + 2.0f*sqrtf(A)*alpha );
494 b[1] = -2.0f*A*( (A-1.0f) + (A+1.0f) * cosf(w0) );
495 b[2] = A*( (A+1.0f) + (A-1.0f) * cosf(w0) - 2.0f*sqrtf(A)*alpha );
496 a0 = (A+1.0f) - (A-1.0f) * cosf(w0) + 2.0f*sqrtf(A)*alpha;
497 a[1] = 2.0f*( (A-1.0f) - (A+1.0f) * cosf(w0) );
498 a[2] = (A+1.0f) - (A-1.0f) * cosf(w0) - 2.0f*sqrtf(A)*alpha;
499
500 /* Scale by a0, since applyBiQuadFilter() and applyIIR() assume a0 = 1.0 */
501 b[0] /= a0;
502 b[1] /= a0;
503 b[2] /= a0;
504 a[1] /= a0;
505 a[2] /= a0;
506 break;
507
509 /* Filter design equations - DAFX (2nd ed) p66 */
510 K = tanf(SAF_PI * fc/fs);
511 V0 = powf(10.0f, (gain_dB/20.0f));
512 KK = K * K;
513 if (gain_dB > 0.0f){
514 D = 1.0f + (K/Q) + KK;
515 b[0] = (1.0f + (V0/Q) * K + KK)/D;
516 b[1] = (2.0f*(KK - 1.0f))/D;
517 b[2] = (1.0f - (V0/Q) * K + KK)/D;
518 a[1] = b[1];
519 a[2] = (1.0f - (K/Q) + KK)/D;
520 }
521 else {
522 D = 1.0f + (K/(V0*Q)) + KK;
523 b[0] = (1.0f + (K/Q) + KK)/D;
524 b[1] = (2.0f*(KK - 1.0f))/D;
525 b[2] = (1.0f - (K/Q) + KK)/D;
526 a[1] = b[1];
527 a[2] = (1.0f - (K/(V0*Q)) + KK)/D;
528 }
529 break;
530
532 /* Filter design equations - https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html */
533 A = powf(10.0f, gain_dB/40.0f);
534 w0 = 2.0f*SAF_PI*fc/fs;
535 alpha = sinf(w0)/(2.0f*Q);
536 b[0] = 1.0f + alpha*A;
537 b[1] = -2.0f*cosf(w0);
538 b[2] = 1.0f - alpha*A;
539 a0 = 1.0f + alpha/A;
540 a[1] = b[1];
541 a[2] = 1.0f - alpha/A;
542
543 /* Scale by a0, since applyBiQuadFilter() and applyIIR() assume a0 = 1.0 */
544 b[0] /= a0;
545 b[1] /= a0;
546 b[2] /= a0;
547 a[1] /= a0;
548 a[2] /= a0;
549 break;
550 }
551}
552
554(
555 float b[3],
556 float a[3],
557 float w_z_12[2],
558 float* signal,
559 int nSamples
560)
561{
562 int n;
563 float wn;
564
565 /* biquad difference equation (Direct form 2) */
566 for(n=0; n<nSamples; n++){
567 wn = signal[n] - a[1] * w_z_12[0] - a[2] * w_z_12[1];
568 signal[n] = b[0] * wn + b[1] * w_z_12[0] + b[2] * w_z_12[1];
569 /* shuffle delays */
570 w_z_12[1] = w_z_12[0];
571 w_z_12[0] = wn;
572 }
573}
574
576(
577 float b[3],
578 float a[3],
579 float* freqs,
580 int nFreqs,
581 float fs,
582 int mag2dB,
583 float* magnitude,
584 float* phase_rad
585)
586{
587 int ff;
588 float w, denom_real, denom_imag, num_real, num_imag;
589
590 for(ff=0; ff<nFreqs; ff++){
591 w = tanf(SAF_PI * freqs[ff]/fs);
592 /* substituting Euler, z = e^(-jwn) = cos(wn) + j*sin(wn), into:
593 * H(z) = (b0 + b1*z^(-1) + b2*z^(-2)) / (1 + a1*z^(-1) + a2*z^(-2)): */
594 denom_real = 1.0f + a[1]*cosf(w) + a[2]*cosf(2.0f*w);
595 denom_imag = a[1]*sinf(w) + a[2]*sinf(2.0f*w);
596 num_real = b[0] + b[1]*cosf(w) + b[2]*cosf(2.0f*w);
597 num_imag = b[1]*sinf(w) + b[2]*sinf(2.0f*w);
598
599 if(magnitude!=NULL){
600 magnitude[ff] = sqrtf( (powf(num_real, 2.0f) + powf(num_imag, 2.0f)) / (powf(denom_real, 2.0f) + powf(denom_imag, 2.0f) + 2.23e-7f) );
601 if(mag2dB)
602 magnitude[ff] = 20.0f*log10f(magnitude[ff]);
603 }
604 if(phase_rad!=NULL)
605 phase_rad[ff] = atan2f(num_imag,num_real) - atan2f(denom_imag, denom_real);
606 }
607}
608
610 (
611 float* b_coeff, /* Note coeffs are *floats* */
612 float* a_coeff,
613 int nCoeffs,
614 float* freqs,
615 int nFreqs,
616 float fs,
617 int mag2dB,
618 float* magnitude,
619 float* phase_rad
620)
621{
622 int ff;
623 float w, x, a, b, c, d, h_re, h_im, cosx, sinx;
624 float norm_frq = -2.f * SAF_PI / fs; // -1 factored in from negated 'n' below
625
626 /*
627 * substitute Euler's z = e^(jwn) = cos(wn) + j*sin(wn)
628 * into
629 * [b0*z^(0) + b1*z^(-1) ... + bn*z^(-n)]
630 * H(z) = --------------------------------------
631 * [a0*z^(0) + a1*z^(-1) ... + an*z^(-n)]
632 */
633
634 for(ff = 0; ff < nFreqs; ff++){
635 w = freqs[ff] * norm_frq;
636
637 // n = 0; real terms are b[0] and a[0], imag terms are 0
638 a = b_coeff[0]; // num_re; b_coeff[0] * cos(x); x = -1.f * n * w;
639 b = 0.0; // num_imag; b_coeff[0] * sin(x);
640 c = a_coeff[0]; // den_re
641 d = 0.0; // den_imag
642
643 /* sum over remaining numerator and denominator terms */
644 for(int n = 1; n < nCoeffs; n++){
645 x = (n * w); // n * -1.f * w (-1.f applied in norm_frq)
646 cosx = cosf(x); // alt: cosx = 1 - 2.f * powf(sinf(x/2.f), 2.f);
647 sinx = sinf(x);
648 a += b_coeff[n] * cosx; // 'a'
649 b += b_coeff[n] * sinx; // 'b'
650 c += a_coeff[n] * cosx; // 'c'
651 d += a_coeff[n] * sinx; // 'd'
652 }
653
654 /* 1 / (c^2 + d^2 + eps) */
655 double dvsr = 1.0 / (powf(c, 2.f) + powf(d, 2.f) + 2.23e-7f);
656
657 if(magnitude!=NULL){
658 /* sqrt((a^2 + b^2) / (c^2 + d^2)) */
659 magnitude[ff] = (float)sqrt( (powf(a, 2.0f) + powf(b, 2.0f)) * dvsr );
660 if(mag2dB)
661 magnitude[ff] = 20.0f*log10f(magnitude[ff]);
662 }
663
664 if(phase_rad!=NULL) {
665 /* complex division */
666 h_re = (a*c + b*d) * (float)dvsr;
667 h_im = (b*c - a*d) * (float)dvsr;
668 phase_rad[ff] = (float)atan2(h_im, h_re);
669 }
670 }
671}
672
674 (
675 double* b_coeff, /* Note coeffs are *doubles* */
676 double* a_coeff,
677 int nCoeffs,
678 float* freqs,
679 int nFreqs,
680 float fs,
681 int mag2dB,
682 float* magnitude,
683 float* phase_rad
684)
685{
686 int ff;
687 float w;
688 double x, a, b, c, d, h_re, h_im, cosx, sinx;
689 float norm_frq = -2.f * SAF_PI / fs; // -1 factored in from negated 'n' below
690
691 /*
692 * substitute Euler's z = e^(jwn) = cos(wn) + j*sin(wn)
693 * into
694 * [b0*z^(0) + b1*z^(-1) ... + bn*z^(-n)]
695 * H(z) = --------------------------------------
696 * [a0*z^(0) + a1*z^(-1) ... + an*z^(-n)]
697 */
698
699 for(ff = 0; ff < nFreqs; ff++){
700 w = freqs[ff] * norm_frq;
701
702 // n = 0; real terms are b[0] and a[0], imag terms are 0
703 a = b_coeff[0]; // num_re; b_coeff[0] * cos(x); x = -1.f * n * w;
704 b = 0.0; // num_imag; b_coeff[0] * sin(x);
705 c = a_coeff[0]; // den_re
706 d = 0.0; // den_imag
707
708 /* sum over remaining numerator and denominator terms */
709 for(int n = 1; n < nCoeffs; n++){
710 x = (double)(n * w); // n * -1.f * w (-1.f applied in norm_frq)
711 cosx = 1 - 2.f * pow(sin(x/2.f), 2.f); // cos(x) = 1 - 2sin^2(x/2)
712 sinx = sin(x);
713 a += b_coeff[n] * cosx; // 'a'
714 b += b_coeff[n] * sinx; // 'b'
715 c += a_coeff[n] * cosx; // 'c'
716 d += a_coeff[n] * sinx; // 'd'
717 }
718
719 /* 1 / (c^2 + d^2 + eps) */
720 double dvsr = 1.0 / (pow(c, 2.f) + pow(d, 2.f) + 2.23e-17f);
721
722 if(magnitude!=NULL){
723 /* sqrt((a^2 + b^2) / (c^2 + d^2)) */
724 magnitude[ff] = (float)sqrt( (pow(a, 2.0f) + pow(b, 2.0f)) * dvsr );
725 if(mag2dB)
726 magnitude[ff] = 20.0f*log10f(magnitude[ff]);
727 }
728
729 if(phase_rad!=NULL) {
730 /* complex division */
731 h_re = (a*c + b*d) * dvsr;
732 h_im = (b*c - a*d) * dvsr;
733 phase_rad[ff] = (float)atan2(h_im, h_re);
734 }
735 }
736}
737
738
740(
741 float* in_signal,
742 int nSamples,
743 int nCoeffs,
744 float* b,
745 float* a,
746 float* wz,
747 float* out_signal
748)
749{
750 int n, i;
751 float wn;
752
753#if defined(SAF_USE_INTEL_IPP) && 0 /* Couldn't get this to give the same/correct result... */
754 int pBufSize;
755 Ipp32f* ba;
756 IppsIIRState_32f* pIppIIR;
757 Ipp8u * m_pBuf;
758 ba = malloc1d(nCoeffs*2*sizeof(Ipp32f));
759 for(i=0; i<nCoeffs; i++){
760 ba[i] = b[i];
761 ba[i+nCoeffs] = a[i];
762 }
763 ippsIIRGetStateSize_32f( nCoeffs-1, &pBufSize );
764 m_pBuf = ippsMalloc_8u(pBufSize);
765
766 pIppIIR = NULL;
767 IppStatus error = ippsIIRInit_32f(&pIppIIR, ba, nCoeffs-1, NULL, m_pBuf);
768 error = ippsIIR_32f( in_signal, out_signal, nSamples, pIppIIR );
769
770 free(ba);
771 ippsFree(m_pBuf);
772
773 return;
774#endif
775
776 /* For compiler speed-ups */
777 switch(nCoeffs){
778 case 1: saf_print_error("Just divide in_signal by b[0]...");
779 case 2: applyIIR_1(in_signal, nSamples, b, a, wz, out_signal); return;
780 case 3: applyIIR_2(in_signal, nSamples, b, a, wz, out_signal); return;
781 case 4: applyIIR_3(in_signal, nSamples, b, a, wz, out_signal); return;
782 }
783
784 /* difference equation (Direct form 2) */
785 for (n=0; n<nSamples; n++){
786 /* numerator */
787 wn = in_signal[n];
788 for (i=1; i<nCoeffs;i++)
789 wn = wn - (a[i] * wz[i-1]);
790
791 /* denominator */
792 out_signal[n] = b[0] * wn;
793 for (i=1; i<nCoeffs; i++)
794 out_signal[n] = out_signal[n] + (b[i] * wz[i-1]);
795
796 /* shuffle delays */
797 switch(nCoeffs-1){
798 case 10: wz[9] = wz[8]; /* fall through */
799 case 9: wz[8] = wz[7]; /* fall through */
800 case 8: wz[7] = wz[6]; /* fall through */
801 case 7: wz[6] = wz[5]; /* fall through */
802 case 6: wz[5] = wz[4]; /* fall through */
803 case 5: wz[4] = wz[3]; /* fall through */
804 case 4: wz[3] = wz[2]; /* fall through */
805 case 3: wz[2] = wz[1]; /* fall through */
806 case 2: wz[1] = wz[0]; /* fall through */
807 case 1: wz[0] = wn; break;
808 default: saf_print_error("Unsupported number of IIR filter coefficients.");
809 }
810 }
811}
812
814(
815 BUTTER_FILTER_TYPES filterType,
816 int order,
817 float cutoff1,
818 float cutoff2,
819 float sampleRate,
820 double* b_coeffs,
821 double* a_coeffs
822)
823{
824 int i, j, k, np, tmp_len, numStates, oddPolesFLAG, nCoeffs;
825 double wlow, whi, w0, wl, w1, BW, Wn1, q;
826 double den[3];
827 double* c_state, *r, *b_coeffs_real;
828 double** a_state, **bf_ss, **tmp1, **tmp2, **a_bili;
829 double_complex kaT, kbT;
830 double_complex den_cmplx[3];
831 double_complex* proto, *proto_tmp, *a_coeffs_cmplx, *kern, *rcmplx, *b_coeffs_cmplx;
832
833 wlow = (double)cutoff1/((double)sampleRate/2.0);
834 whi = (double)cutoff2/((double)sampleRate/2.0);
835 w0 = 4.0 * tan(SAF_PI*wlow/2.0);
836 Wn1 = 0.0;
837
838 /* Compute prototype for Nth order Butterworth analogue lowpass filter */
839 if (order%2 != 0){/* ISODD */
840 tmp_len = (int)((float)order/2.0f); /* floor */
841 np = 2*tmp_len+1;
842 proto = malloc1d(np*sizeof(double_complex));
843 proto[np-1] = cmplx(-1.0,0.0);
844 }
845 else{ /* ISEVEN */
846 tmp_len = order/2;
847 np = 2*tmp_len;
848 proto = malloc1d(np*sizeof(double_complex));
849 }
850 proto_tmp = malloc1d(np*sizeof(double_complex));
851 for(i=1, j=0; i<=order-1; i+=2, j++)
852 proto_tmp[j] = cexp(cmplx(0.0, SAF_PI*(double)i/(2.0*(double)order) + SAF_PI/2.0) );
853 for (i=0; i<tmp_len; i++){
854 proto[2*i] = proto_tmp[i];
855 proto[2*i+1] = conj(proto_tmp[i]);
856 }
857
858 /* Transform prototype into state space */
859 numStates = np;
860 cmplxPairUp(proto, proto_tmp, np);
861 memcpy(proto, proto_tmp, np*sizeof(double_complex));
862 free(proto_tmp);
863 a_state = (double**)calloc2d(numStates,numStates,sizeof(double));
864 c_state = malloc1d(numStates*sizeof(double));
865 if (np%2 != 0){/* ISODD */
866 a_state[0][0] = creal(proto[np-1]);
867 c_state[0] = 1.0;
868 np--;
869 oddPolesFLAG = 1;
870 }
871 else
872 oddPolesFLAG = 0;
873
874 /* Adjust indices as needed */
875 for(i=1; i<np; i+=2){
876 polyz_v(&proto[i-1], den_cmplx, 2);
877 for(j=0; j<3; j++)
878 den[j] = creal(den_cmplx[j]);
879 j = oddPolesFLAG ? i-1 : i-2;
880
881 if(j==-1){
882 a_state[0][0] = -den[1];
883 a_state[0][1] = -den[2];
884 a_state[1][0] = 1.0;
885 a_state[1][1] = 0.0;
886 c_state[0] = 0.0;
887 c_state[1] = 1.0;
888 }
889 else{
890 for(k=0; k<j+1; k++)
891 a_state[j+1][k] = c_state[k];
892 a_state[j+1][j+1] = -den[1];
893 a_state[j+1][j+2] = -den[2];
894 a_state[j+2][j+1] = 1.0;
895 a_state[j+2][j+2] = 0.0;
896
897 for(k=0; k<j+1; k++)
898 c_state[k] = 0.0;
899 c_state[j+1] = 0.0;
900 c_state[j+2] = 1.0;
901 }
902 }
903
904 /* Transform lowpass filter into the desired filter (while in state space) */
905 bf_ss = NULL;
906 switch(filterType){
908 utility_dinv(NULL, FLATTEN2D(a_state), FLATTEN2D(a_state), numStates);
909 /* fall through */
911 bf_ss = (double**)malloc2d(numStates,numStates,sizeof(double));
912 for(i=0; i<numStates; i++)
913 for(j=0; j<numStates; j++)
914 bf_ss[i][j] = w0*(a_state[i][j]);
915 break;
917 utility_dinv(NULL, FLATTEN2D(a_state), FLATTEN2D(a_state), numStates);
918 /* fall through */
920 numStates = numStates*2;
921 w1 = 4.0*tan(SAF_PI*whi/2.0);
922 BW = w1 - w0;
923 Wn1 = sqrt(w0*w1);
924 q = Wn1/BW;
925 bf_ss = (double**)calloc2d(numStates,numStates,sizeof(double));
926 for(i=0; i<numStates/2; i++)
927 for(j=0; j<numStates/2; j++)
928 bf_ss[i][j] = Wn1 * (a_state[i][j]) /q;
929 for(i=numStates/2; i<numStates; i++)
930 for(j=0; j<numStates/2; j++)
931 bf_ss[i][j] = (i-numStates/2) == j ? -Wn1 : 0.0;
932 for(i=0; i<numStates/2; i++)
933 for(j=numStates/2; j<numStates; j++)
934 bf_ss[i][j] = i == (j-numStates/2) ? Wn1 : 0.0;
935 break;
936 }
937 nCoeffs = numStates+1;
938
939 /* Bilinear transformation to find the discrete equivalent of the filter */
940 tmp1 = (double**)malloc2d(numStates,numStates,sizeof(double));
941 tmp2 = (double**)malloc2d(numStates,numStates,sizeof(double));
942 a_bili = (double**)malloc2d(numStates,numStates,sizeof(double));
943 for(i=0; i<numStates; i++){
944 for(j=0; j<numStates; j++){
945 tmp1[i][j] = (i==j ? 1.0f : 0.0f) + bf_ss[i][j]*0.25;
946 tmp2[i][j] = (i==j ? 1.0f : 0.0f) - bf_ss[i][j]*0.25;
947 }
948 }
949 utility_dglslv(NULL, FLATTEN2D(tmp2), numStates, FLATTEN2D(tmp1), numStates, FLATTEN2D(a_bili));
950
951 /* Compute the filter coefficients for the numerator and denominator */
952 a_coeffs_cmplx = malloc1d(nCoeffs*sizeof(double_complex));
953 polyd_m(FLATTEN2D(a_bili), a_coeffs_cmplx, numStates);
954 rcmplx = NULL;
955 r = NULL;
956 switch(filterType){
957 default:
958 /* fall through */
960 r = malloc1d(numStates*sizeof(double));
961 for(i=0; i<numStates; i++)
962 r[i] = -1.0;
963 wl = 0.0;
964 break;
966 r = malloc1d(numStates*sizeof(double));
967 for(i=0; i<numStates; i++)
968 r[i] = 1.0;
969 wl = SAF_PI;
970 break;
972 r = malloc1d(numStates*sizeof(double));
973 wl = 2.0*atan2(Wn1, 4.0);
974 for(i=0; i<order;i++)
975 r[i] = 1.0;
976 for(; i<2*order;i++)
977 r[i] = -1.0;
978 break;
980 rcmplx = malloc1d(numStates*sizeof(double_complex));
981 Wn1 = 2.0*atan2(Wn1,4.0);
982 wl = 0.0;
983 for(i=0; i<numStates;i++)
984 rcmplx[i] = cexp(cmplx(0.0, Wn1*pow(-1.0,(double)i)));
985 break;
986 }
987 b_coeffs_real = malloc1d(nCoeffs*sizeof(double));
988 if(filterType == BUTTER_FILTER_BSF){
989 b_coeffs_cmplx = malloc1d(nCoeffs*sizeof(double_complex));
990 polyz_v(rcmplx, b_coeffs_cmplx, numStates);
991 for(i=0; i<nCoeffs; i++)
992 b_coeffs_real[i] = creal(b_coeffs_cmplx[i]);
993 free(b_coeffs_cmplx);
994 }
995 else
996 polyd_v(r, b_coeffs_real, numStates);
997 kern = calloc1d(nCoeffs,sizeof(double_complex));
998 kaT = cmplx(0.0,0.0);
999 kbT = cmplx(0.0,0.0);
1000 for(i=0; i<nCoeffs; i++){
1001 kern[i] = cexp(cmplx(0.0,-wl*(double)i));
1002 kaT = ccadd(kaT, crmul(kern[i],creal(a_coeffs_cmplx[i])));
1003 kbT = ccadd(kbT, crmul(kern[i],b_coeffs_real[i]));
1004 }
1005
1006 /* output */
1007 for(i=0; i<nCoeffs; i++){
1008 b_coeffs[i] = creal(crmul(ccdiv(kaT,kbT), b_coeffs_real[i]));
1009 a_coeffs[i] = creal(a_coeffs_cmplx[i]);
1010 }
1011
1012 /* clean-up */
1013 free(proto);
1014 free(a_state);
1015 free(c_state);
1016 free(bf_ss);
1017 free(tmp1);
1018 free(tmp2);
1019 free(a_bili);
1020 free(a_coeffs_cmplx);
1021 free(b_coeffs_real);
1022 free(kern);
1023}
1024
1026typedef struct _faf_IIRFB_data{
1033 float** b_lpf;
1034 float** a_lpf;
1035 float** b_hpf;
1036 float** a_hpf;
1037 float*** wz_lpf;
1038 float*** wz_hpf;
1039 float*** wz_apf1;
1040 float*** wz_apf2;
1041 float* tmp;
1042 float* tmp2;
1045
1047(
1048 void** phFaF,
1049 int order,
1050 float* fc,
1051 int nCutoffFreq,
1052 float sampleRate,
1053 int maxNumSamples
1054)
1055{
1056 *phFaF = malloc1d(sizeof(faf_IIRFB_data));
1057 faf_IIRFB_data *fb = (faf_IIRFB_data*)(*phFaF);
1058 double b_lpf[4], a_lpf[4], b_hpf[4], a_hpf[4], r[7], revb[4], reva[4], q[4];
1059 double tmp[7], tmp2[7];
1060 double_complex d1[3], d2[3], d1_num[3], d2_num[3];
1061 double_complex z[3], A[3][3], ztmp[7], ztmp2[7];
1062 int i, j, f, filtLen, d1_len, d2_len;
1063
1064 saf_assert( (order==1) || (order==3), "Only odd number orders are supported, and 5th order+ is numerically unstable");
1065 saf_assert(nCutoffFreq>1, "Number of filterbank cut-off frequencies must be more than 1");
1066 filtLen = order + 1;
1067 fb->filtOrder = order;
1068 fb->filtLen = filtLen;
1069
1070 /* Number of bands is always one more than the number of cut-off
1071 * frequencies */
1072 fb->nFilters = nCutoffFreq;
1073 fb->nBands = nCutoffFreq + 1;
1074
1075 /* Allocate memory for filter coefficients and delay buffers */
1076 fb->b_hpf = (float**)malloc2d(nCutoffFreq, filtLen, sizeof(float));
1077 fb->a_hpf = (float**)malloc2d(nCutoffFreq, filtLen, sizeof(float));
1078 fb->b_lpf = (float**)malloc2d(nCutoffFreq, filtLen, sizeof(float));
1079 fb->a_lpf = (float**)malloc2d(nCutoffFreq, filtLen, sizeof(float));
1080 fb->wz_hpf = (float***)calloc3d(fb->nBands, nCutoffFreq, order, sizeof(float));
1081 fb->wz_lpf = (float***)calloc3d(fb->nBands, nCutoffFreq, order, sizeof(float));
1082 fb->wz_apf1 = (float***)calloc3d(fb->nBands, nCutoffFreq, order, sizeof(float));
1083 fb->wz_apf2 = (float***)calloc3d(fb->nBands, nCutoffFreq, order, sizeof(float));
1084 fb->maxNSamplesToExpect = maxNumSamples;
1085 fb->tmp = malloc1d(maxNumSamples*sizeof(float));
1086 fb->tmp2 = malloc1d(maxNumSamples*sizeof(float));
1087
1088 /* Compute low-pass and complementary high-pass filter coefficients for each
1089 * cut-off frequency */
1090 for(f=0; f<nCutoffFreq; f++){
1091 /* Low-pass filter */
1092 butterCoeffs(BUTTER_FILTER_LPF, order, fc[f], 0.0f, sampleRate, (double*)b_lpf, (double*)a_lpf);
1093
1094 /* IIR power complementary filter design (i.e. High-pass) */
1095 for(i=0; i<filtLen; i++){
1096 reva[i] = a_lpf[filtLen-i-1];
1097 revb[i] = b_lpf[filtLen-i-1];
1098 }
1099 convd(revb, b_lpf, filtLen, filtLen, tmp);
1100 convd(a_lpf, reva, filtLen, filtLen, tmp2);
1101 for(i=0; i<2*filtLen-1; i++)
1102 r[i] = tmp[i] - tmp2[i];
1103 q[0] = sqrt(-r[0]/-1.0);
1104 q[1] = -r[1]/(2.0*-1.0*q[0]);
1105 if(order==3){
1106 //q[3]=conj(-1.0*q[0]);
1107 //q[2]=conj(-1.0*q[1]);
1108 q[3] = -1.0*q[0];
1109 q[2] = -1.0*q[1];
1110 }
1111 for(i=0; i<filtLen; i++)
1112 q[i] = b_lpf[i] - q[i];
1113
1114 /* Find roots of polynomial */
1115 if(order==1)
1116 z[0] = cmplx(-q[1]/q[0], 0.0);
1117 else if(order==3){
1118 memset(A, 0, 9*sizeof(double_complex));
1119 A[0][0] = cmplx(-q[1]/q[0], 0.0);
1120 A[0][1] = cmplx(-q[2]/q[0], 0.0);
1121 A[0][2] = cmplx(-q[3]/q[0], 0.0);
1122 A[1][0] = cmplx(1.0, 0.0);
1123 A[2][1] = cmplx(1.0, 0.0);
1124 utility_zeig(NULL, (double_complex*)A, 3, NULL, NULL, NULL, (double_complex*)z);
1125 }
1126
1127 /* Separate the zeros inside the unit circle and the ones outside to
1128 * form the allpass functions */
1129 d1[0] = cmplx(1.0, 0.0);
1130 d2[0] = cmplx(1.0, 0.0);
1131 d1_len = d2_len = 1;
1132 for(i=0; i<order; i++){
1133 if (cabs(z[i]) < 1.0){
1134 ztmp[0] = cmplx(1.0, 0.0);
1135 ztmp[1] = crmul(z[i], -1.0);
1136 convz(d2,ztmp,d2_len,2,ztmp2);
1137 d2_len++;
1138 for(j=0; j<d2_len; j++)
1139 d2[j] = ztmp2[j];
1140 }
1141 else{
1142 ztmp[0] = cmplx(1.0, 0.0);
1143 ztmp[1] = ccdiv(cmplx(-1.0, 0.0), conj(z[i]));
1144 convz(d1,ztmp,d1_len,2,ztmp2);
1145 d1_len++;
1146 for(j=0; j<d1_len; j++)
1147 d1[j] = ztmp2[j];
1148 }
1149 }
1150
1151 /* Convert coupled allpass filter to transfer function form (code from:
1152 * https://github.com/nsk1001/Scilab-functions written by Nagma Samreen
1153 * Khan) */
1154 for(i=0; i<d1_len; i++)
1155 d1_num[i] = conj(d1[d1_len-i-1]);
1156 for(i=0; i<d2_len; i++)
1157 d2_num[i] = conj(d2[d2_len-i-1]);
1158 convz(d1_num, d2, d1_len, d2_len, ztmp);
1159 convz(d2_num, d1, d2_len, d1_len, ztmp2);
1160 for(i=0; i<filtLen; i++){
1161 b_hpf[i] = -0.5 * creal(ccsub(ztmp[filtLen-i-1], ztmp2[filtLen-i-1]));
1162 a_hpf[i] = a_lpf[i];
1163 }
1164
1165 /* Store in single precision for run-time */
1166 for(i=0; i<filtLen; i++){
1167 fb->b_hpf[f][i] = (float)b_hpf[i];
1168 fb->a_hpf[f][i] = (float)a_hpf[i];
1169 fb->b_lpf[f][i] = (float)b_lpf[i];
1170 fb->a_lpf[f][i] = (float)a_lpf[i];
1171 }
1172 }
1173}
1174
1176(
1177 void* hFaF,
1178 float* inSig,
1179 float** outBands,
1180 int nSamples
1181)
1182{
1183 faf_IIRFB_data *fb = (faf_IIRFB_data*)(hFaF);
1184 int band,j;
1185
1186 saf_assert(nSamples <= fb->maxNSamplesToExpect, "Number of samples exceeds the maximum number informed when calling faf_IIRFilterbank_create()");
1187
1188 /* Copy input signal to all output bands/channels */
1189 for(band=0; band<fb->nBands; band++)
1190 memcpy(outBands[band], inSig, nSamples*sizeof(float));
1191
1192 /* Band 0 */
1193 for (j = 0; j<fb->nFilters; j++)
1194 applyIIR(outBands[0], nSamples, fb->filtLen, fb->b_lpf[j], fb->a_lpf[j], fb->wz_lpf[0][j], outBands[0]);
1195
1196 /* Band 1 */
1197 applyIIR(outBands[1], nSamples, fb->filtLen, fb->b_hpf[0], fb->a_hpf[0], fb->wz_hpf[1][0], outBands[1]);
1198 for (j = 1; j<fb->nFilters; j++)
1199 applyIIR(outBands[1], nSamples, fb->filtLen, fb->b_lpf[j], fb->a_lpf[j], fb->wz_lpf[1][j], outBands[1]);
1200
1201 /* All-pass filters (bands 2..N-1) */
1202 for (band = 2; band < fb->nBands; band++){
1203 for (j=0; j<=band-2; j++){
1204 applyIIR(outBands[band], nSamples, fb->filtLen, fb->b_lpf[j], fb->a_lpf[j], fb->wz_apf1[band][j], fb->tmp);
1205 applyIIR(outBands[band], nSamples, fb->filtLen, fb->b_hpf[j], fb->a_hpf[j], fb->wz_apf2[band][j], fb->tmp2);
1206 utility_svvadd(fb->tmp, fb->tmp2, nSamples, outBands[band]);
1207 }
1208 }
1209
1210 /* Bands 2..N-2 */
1211 for(band = 2; band< fb->nBands-1; band++){
1212 /* high-pass filter */
1213 applyIIR(outBands[band], nSamples, fb->filtLen, fb->b_hpf[band-1], fb->a_hpf[band-1], fb->wz_hpf[band][band-1], outBands[band]);
1214
1215 /* low-pass filters */
1216 for(j=band; j<fb->nBands-1; j++)
1217 applyIIR(outBands[band], nSamples, fb->filtLen, fb->b_lpf[j], fb->a_lpf[j], fb->wz_lpf[band][j], outBands[band]);
1218 }
1219
1220 /* Band N-1 */
1221 if (fb->nBands>2){
1222 applyIIR(outBands[fb->nBands-1], nSamples, fb->filtLen, fb->b_hpf[fb->nFilters-1], fb->a_hpf[fb->nFilters-1],
1223 fb->wz_hpf[fb->nBands-1][fb->nFilters-1], outBands[fb->nBands-1]);
1224 }
1225}
1226
1228(
1229 void* hFaF
1230)
1231{
1232 faf_IIRFB_data *fb = (faf_IIRFB_data*)(hFaF);
1233
1234 memset(FLATTEN3D(fb->wz_hpf), 0, (fb->nBands) * (fb->nFilters) * (fb->filtOrder) * sizeof(float));
1235 memset(FLATTEN3D(fb->wz_lpf), 0, (fb->nBands) * (fb->nFilters) * (fb->filtOrder) * sizeof(float));
1236 memset(FLATTEN3D(fb->wz_apf1), 0, (fb->nBands) * (fb->nFilters) * (fb->filtOrder) * sizeof(float));
1237 memset(FLATTEN3D(fb->wz_apf2), 0, (fb->nBands) * (fb->nFilters) * (fb->filtOrder) * sizeof(float));
1238}
1239
1241(
1242 void** phFaF
1243)
1244{
1245 faf_IIRFB_data *fb = (faf_IIRFB_data*)(*phFaF);
1246
1247 if(fb!=NULL){
1248 free(fb->b_hpf);
1249 free(fb->a_hpf);
1250 free(fb->b_lpf);
1251 free(fb->a_lpf);
1252 free(fb->wz_lpf);
1253 free(fb->wz_hpf);
1254 free(fb->wz_apf1);
1255 free(fb->wz_apf2);
1256 free(fb->tmp);
1257 free(fb->tmp2);
1258 fb=NULL;
1259 *phFaF = NULL;
1260 }
1261}
1262
1263
1264/* ========================================================================== */
1265/* FIR Filter Functions */
1266/* ========================================================================== */
1267
1269(
1270 FIR_FILTER_TYPES filterType,
1271 int order,
1272 float fc1,
1273 float fc2, /* only needed for band-pass/stop */
1274 float fs,
1275 WINDOWING_FUNCTION_TYPES windowType,
1276 int scalingFLAG,
1277 float* h_filt
1278)
1279{
1280 int i, h_len;
1281 float ft1, ft2, h_sum, f0;
1282 float_complex h_z_sum;
1283
1284 h_len = order + 1;
1285 ft1 = fc1/fs;
1286
1287 /* compute filter weights */
1288 if(order % 2 == 0){
1289 /* if order is multiple of 2 */
1290 switch(filterType){
1291 case FIR_FILTER_LPF:
1292 for(i=0; i<h_len; i++)
1293 h_filt[i] = i==order/2 ? 2.0f*ft1 : sinf(2.0f*SAF_PI*ft1*(float)(i-order/2)) / (SAF_PI*(float)(i-order/2));
1294 break;
1295
1296 case FIR_FILTER_HPF:
1297 for(i=0; i<h_len; i++)
1298 h_filt[i] = i==order/2 ? 1.0f - 2.0f*ft1 : -sinf(2.0f*ft1*SAF_PI*(float)(i-order/2)) / (SAF_PI*(float)(i-order/2));
1299 break;
1300
1301 case FIR_FILTER_BPF:
1302 ft2 = fc2/fs;
1303 for(i=0; i<h_len; i++){
1304 h_filt[i] = i==order/2 ? 2.0f*(ft2-ft1) :
1305 sinf(2.0f*SAF_PI*ft2*(float)(i-order/2)) / (SAF_PI*(float)(i-order/2)) - sinf(2.0f*SAF_PI*ft1*(float)(i-order/2)) / (SAF_PI*(float)(i-order/2));
1306 }
1307 break;
1308
1309 case FIR_FILTER_BSF:
1310 ft2 = fc2/fs;
1311 for(i=0; i<h_len; i++){
1312 h_filt[i] = i==order/2 ? 1.0f - 2.0f*(ft2-ft1) :
1313 sinf(2.0f*SAF_PI*ft1*(float)(i-order/2)) / (SAF_PI*(float)(i-order/2)) - sinf(2.0f*SAF_PI*ft2*(float)(i-order/2)) / (SAF_PI*(float)(i-order/2));
1314 }
1315 break;
1316 }
1317 }
1318 else
1319 saf_print_error("Please specify an even value for the filter 'order' argument");
1320
1321 /* Apply windowing function */
1322 applyWindowingFunction(windowType, h_len, h_filt);
1323
1324 /* Scaling, to ensure pass-band is truely at 1 (0dB).
1325 * [1] "Programs for Digital Signal Processing", IEEE Press John Wiley &
1326 * Sons, 1979, pg. 5.2-1.
1327 */
1328 if(scalingFLAG){
1329 switch(filterType){
1330 case FIR_FILTER_LPF:
1331 case FIR_FILTER_BSF:
1332 h_sum = 0.0f;
1333 for(i=0; i<h_len; i++)
1334 h_sum += h_filt[i];
1335 for(i=0; i<h_len; i++)
1336 h_filt[i] /= h_sum;
1337 break;
1338
1339 case FIR_FILTER_HPF:
1340 f0 = 1.0f;
1341 h_z_sum = cmplxf(0.0f, 0.0f);
1342 for(i=0; i<h_len; i++)
1343 h_z_sum = ccaddf(h_z_sum, crmulf(cexpf(cmplxf(0.0f, -2.0f*SAF_PI*(float)i*f0/2.0f)), h_filt[i]));
1344 h_sum = cabsf(h_z_sum);
1345 for(i=0; i<h_len; i++)
1346 h_filt[i] /= h_sum;
1347 break;
1348
1349 case FIR_FILTER_BPF:
1350 f0 = fc1/fs + fc2/fs;
1351 h_z_sum = cmplxf(0.0f, 0.0f);
1352 for(i=0; i<h_len; i++)
1353 h_z_sum = ccaddf(h_z_sum, crmulf(cexpf(cmplxf(0.0f, -2.0f*SAF_PI*(float)i*f0/2.0f)), h_filt[i]));
1354 h_sum = cabsf(h_z_sum);
1355 for(i=0; i<h_len; i++)
1356 h_filt[i] /= h_sum;
1357 break;
1358 }
1359 }
1360}
1361
1363(
1364 int order,
1365 float* fc, /* cut-off frequencies; nCutoffFreq x 1 */
1366 int nCutoffFreq,
1367 float sampleRate,
1368 WINDOWING_FUNCTION_TYPES windowType,
1369 int scalingFLAG,
1370 float* filterbank /* (nCutoffFreq+1) x (order+1) */
1371)
1372{
1373 int k, nFilt;
1374
1375 /* Number of filters returned is always one more than the number of cut-off frequencies */
1376 nFilt = nCutoffFreq + 1;
1377
1378 /* first and last bands are low-pass and high pass filters, using the first
1379 * and last cut-off frequencies in vector 'fc', respectively. */
1380 FIRCoeffs(FIR_FILTER_LPF, order, fc[0], 0.0f, sampleRate, windowType, scalingFLAG, filterbank);
1381 FIRCoeffs(FIR_FILTER_HPF, order, fc[nCutoffFreq-1], 0.0f, sampleRate, windowType, scalingFLAG, &filterbank[(nFilt-1)*(order+1)]);
1382
1383 /* the inbetween bands are then band-pass filters: */
1384 if(nCutoffFreq>1){
1385 for(k=1; k<nFilt-1; k++)
1386 FIRCoeffs(FIR_FILTER_BPF, order, fc[k-1], fc[k], sampleRate, windowType, scalingFLAG, &filterbank[k*(order+1)]);
1387 }
1388}
1389
#define saf_print_error(message)
Macro to print a error message along with the filename and line number.
void faf_IIRFilterbank_destroy(void **phFaF)
Destroys an instance of the Favrot & Faller filterbank.
void utility_dinv(void *const hWork, double *A, double *B, const int N)
Matrix inversion: double precision, i.e.
#define saf_assert(x, message)
Macro to make an assertion, along with a string explaining its purpose.
#define SAF_PI
pi constant (single precision)
WINDOWING_FUNCTION_TYPES
Windowing function types.
BUTTER_FILTER_TYPES
Butterworth Infinite Impulse Response (IIR) filter design options.
FIR_FILTER_TYPES
Finite Impulse Response (FIR) filter design options.
#define SAF_MAX(a, b)
Returns the maximum of the two values.
void utility_dglslv(void *const hWork, const double *A, const int dim, double *B, int nCol, double *X)
General linear solver: double precision, i.e.
void saf_fft_backward(void *const hFFT, float_complex *inputFD, float_complex *outputTD)
Performs the backward-FFT operation; use for complex to complex transformations.
BIQUAD_FILTER_TYPES
Bi-quadratic (second-order) IIR filter design options.
void FIRFilterbank(int order, float *fc, int nCutoffFreq, float sampleRate, WINDOWING_FUNCTION_TYPES windowType, int scalingFLAG, float *filterbank)
Computes a bank of FIR filter coefficients required to divide a signal into frequency bands.
void cmplxPairUp(double_complex *in_vec, double_complex *out_vec, int len)
Pairs up complex numbers and sorts them in ascending order based on their real parts first,...
void saf_fft_create(void **const phFFT, int N)
Creates an instance of saf_fft; complex<->complex FFT.
void hilbert(float_complex *x, int x_len, float_complex *y)
Computes the discrete-time analytic signal via the Hilbert transform [1].
void faf_IIRFilterbank_create(void **phFaF, int order, float *fc, int nCutoffFreq, float sampleRate, int maxNumSamples)
Computes a bank of IIR filter coefficients required to divide a signal into frequency bands,...
void applyIIR(float *in_signal, int nSamples, int nCoeffs, float *b, float *a, float *wz, float *out_signal)
Applies an IIR filter to a time-domain signal (using the direct form II difference equation)
void saf_rfft_create(void **const phFFT, int N)
Creates an instance of saf_rfft; real<->half-complex (conjugate-symmetric) FFT.
void getWindowingFunction(WINDOWING_FUNCTION_TYPES type, int winlength, float *win)
Computes the weights of a specific windowing function.
void flattenMinphase(float *x, int len)
Equalises input sequence by its minimum phase form, in order to bring its magnitude response to unity...
void saf_fft_forward(void *const hFFT, float_complex *inputTD, float_complex *outputFD)
Performs the forward-FFT operation; use for complex to complex transformations.
void evalIIRTransferFunctionf(float *b_coeff, float *a_coeff, int nCoeffs, float *freqs, int nFreqs, float fs, int mag2dB, float *magnitude, float *phase_rad)
Computes magnitude and phase response of an IIR filter from its coefficients (floats) at user-specifi...
void polyd_m(double *X, double_complex *poly, int size_x)
Convert roots of a matrix to polynomial (real double precision)
float convertQ2BW(float Q)
Converts filter Q-factor to octave band-width.
void utility_zeig(void *const hWork, const double_complex *A, const int dim, double_complex *VL, double_complex *VR, double_complex *D, double_complex *eig)
Eigenvalue decomposition of a NON-SYMMETRIC matrix: double precision complex, i.e.
void saf_rfft_forward(void *const hFFT, float *inputTD, float_complex *outputFD)
Performs the forward-FFT operation; use for real to complex (conjugate symmetric) transformations.
void applyBiQuadFilter(float b[3], float a[3], float w_z_12[2], float *signal, int nSamples)
Applies biQuad filter to an input signal using the direct form II difference equation: https://en....
void biQuadCoeffs(BIQUAD_FILTER_TYPES filterType, float fc, float fs, float Q, float gain_dB, float b[3], float a[3])
Calculates 2nd order IIR filter coefficients [1].
void saf_rfft_backward(void *const hFFT, float_complex *inputFD, float *outputTD)
Performs the backward-FFT operation; use for complex (conjugate symmetric) to real transformations.
void saf_rfft_destroy(void **const phFFT)
Destroys an instance of saf_rfft.
void FIRCoeffs(FIR_FILTER_TYPES filterType, int order, float fc1, float fc2, float fs, WINDOWING_FUNCTION_TYPES windowType, int scalingFLAG, float *h_filt)
Computes FIR filter coefficients by windowing.
void butterCoeffs(BUTTER_FILTER_TYPES filterType, int order, float cutoff1, float cutoff2, float sampleRate, double *b_coeffs, double *a_coeffs)
Computes Butterworth IIR filter coefficients [1].
void evalBiQuadTransferFunction(float b[3], float a[3], float *freqs, int nFreqs, float fs, int mag2dB, float *magnitude, float *phase_rad)
Evaluates the 2nd order IIR transfer function at one or more frequencies, returning its magnitude and...
void convd(double *x, double *h, int len_x, int len_h, double *y)
Basic 1-D direct convolution in the time-domain (real double precision)
void utility_svvadd(const float *a, const float *b, const int len, float *c)
Single-precision, vector-vector addition, i.e.
void polyd_v(double *x, double *poly, int len_x)
Convert roots of a vector to polynomial (real double precision)
void polyz_v(double_complex *x, double_complex *poly, int len_x)
Convert roots of a vector to polynomial (complex double precision)
void faf_IIRFilterbank_flushBuffers(void *hFaF)
Zeros the delay lines used during faf_IIRFilterbank_apply()
float convertBW2Q(float BW)
Converts filter octave band-width to Q-factor.
void evalIIRTransferFunction(double *b_coeff, double *a_coeff, int nCoeffs, float *freqs, int nFreqs, float fs, int mag2dB, float *magnitude, float *phase_rad)
Computes magnitude and phase response of an IIR filter from its coefficients at user-specified freque...
void interpolateFiltersH(int inFFTsize, int outFFTsize, int nFilters, float_complex *filters_in, float_complex *filters_out)
Interpolate filters (w.r.t.
void saf_fft_destroy(void **const phFFT)
Destroys an instance of saf_fft.
void convz(double_complex *x, double_complex *h, int len_x, int len_h, double_complex *y)
Basic 1-D direct convolution in the time-domain (complex double precision)
void getOctaveBandCutoffFreqs(float *centreFreqs, int nCentreFreqs, float *cutoffFreqs)
Converts octave band CENTRE frequencies into CUTOFF frequencies.
void faf_IIRFilterbank_apply(void *hFaF, float *inSig, float **outBands, int nSamples)
Applies the Favrot & Faller filterbank.
@ WINDOWING_FUNCTION_RECTANGULAR
Rectangular.
@ WINDOWING_FUNCTION_BLACKMAN_NUTTALL
Blackman-Nuttall.
@ WINDOWING_FUNCTION_BLACKMAN
Blackman.
@ WINDOWING_FUNCTION_BARTLETT
Bartlett.
@ WINDOWING_FUNCTION_HANN
Hann.
@ WINDOWING_FUNCTION_HAMMING
Hamming.
@ WINDOWING_FUNCTION_NUTTALL
Nuttall.
@ WINDOWING_FUNCTION_BLACKMAN_HARRIS
Blackman-Harris.
@ BUTTER_FILTER_BSF
band-stop filter
@ BUTTER_FILTER_LPF
low-pass filter
@ BUTTER_FILTER_HPF
high-pass filter
@ BUTTER_FILTER_BPF
band-pass filter
@ FIR_FILTER_BSF
band-stop filter
@ FIR_FILTER_LPF
low-pass filter
@ FIR_FILTER_HPF
high-pass filter
@ FIR_FILTER_BPF
band-pass filter
@ BIQUAD_FILTER_LPF
low-pass filter (DAFx-Zolzer)
@ BIQUAD_FILTER_LOW_SHELF_EQCB
low-shelving filter (EQ-cookbook)
@ BIQUAD_FILTER_PEAK
peaking filter (DAFx-Zolzer)
@ BIQUAD_FILTER_HPF_EQCB
high-pass filter (EQ-cookbook)
@ BIQUAD_FILTER_PEAK_EQCB
peaking filter (EQ-cookbook)
@ BIQUAD_FILTER_LOW_SHELF
low-shelving filter (DAFx-Zolzer)
@ BIQUAD_FILTER_LPF_EQCB
low-pass filter (EQ-cookbook)
@ BIQUAD_FILTER_HI_SHELF_EQCB
high-shelving filter (EQ-cookbook)
@ BIQUAD_FILTER_HI_SHELF
high-shelving filter (DAFx-Zolzer)
@ BIQUAD_FILTER_HPF
high-pass filter (DAFx-Zolzer)
void ** malloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D malloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:89
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
Definition md_malloc.c:59
void * calloc1d(size_t dim1, size_t data_size)
1-D calloc (same as calloc, but with error checking)
Definition md_malloc.c:69
void ** calloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D calloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:102
void *** calloc3d(size_t dim1, size_t dim2, size_t dim3, size_t data_size)
3-D calloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:170
#define FLATTEN2D(A)
Use this macro when passing a 2-D dynamic multi-dimensional array to memset, memcpy or any other func...
Definition md_malloc.h:65
#define FLATTEN3D(A)
Use this macro when passing a 3-D dynamic multi-dimensional array to memset, memcpy or any other func...
Definition md_malloc.h:72
Include header for SAF externals.
Main header for the utilities module (SAF_UTILITIES_MODULE)
static void applyIIR_1(float *in_signal, int nSamples, float *b, float *a, float *wz, float *out_signal)
Applies IIR filter of order 1.
static void applyWindowingFunction(WINDOWING_FUNCTION_TYPES type, int winlength, float *x)
Applies a windowing function (see WINDOWING_FUNCTION_TYPES enum) of length 'winlength',...
static void applyIIR_2(float *in_signal, int nSamples, float *b, float *a, float *wz, float *out_signal)
Applies IIR filter of order 2.
static void applyIIR_3(float *in_signal, int nSamples, float *b, float *a, float *wz, float *out_signal)
Applies IIR filter of order 3.
Main structure for the Favrot&Faller filterbank.
float *** wz_hpf
Delay buffers for high-pass filters.
int filtOrder
Filter order (must be 1 or 3)
float ** a_hpf
Denominator filter coeffs for high-pass filters.
int nBands
Number of bands in the filterbank.
float * tmp2
Temporary buffer; maxNSamplesToExpect x 1.
int maxNSamplesToExpect
Maximum number of samples to expect to process at a time.
int filtLen
Filter length.
float * tmp
Temporary buffer; maxNSamplesToExpect x 1.
float *** wz_apf1
Delay buffers for all-pass filter part 1.
float *** wz_lpf
Delay buffers for low-pass filters.
float ** a_lpf
Denominator filter coeffs for low-pass filters.
float *** wz_apf2
Delay buffers for all-pass filter part 2.
int nFilters
Number of filters used by the filterbank.
float ** b_lpf
Numerator filter coeffs for low-pass filters.
float ** b_hpf
Numerator filter coeffs for high-pass filters.