OLD | NEW |
1 // A biquad filter has a z-transform of | 1 // A biquad filter has a z-transform of |
2 // H(z) = (b0 + b1 / z + b2 / z^2) / (1 + a1 / z + a2 / z^2) | 2 // H(z) = (b0 + b1 / z + b2 / z^2) / (1 + a1 / z + a2 / z^2) |
3 // | 3 // |
4 // The formulas for the various filters were taken from | 4 // The formulas for the various filters were taken from |
5 // http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt. | 5 // http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt. |
6 | 6 |
7 | 7 |
8 // Lowpass filter. | 8 // Lowpass filter. |
9 function createLowpassFilter(freq, q, gain) { | 9 function createLowpassFilter(freq, q, gain) { |
10 var b0; | 10 var b0; |
11 var b1; | 11 var b1; |
12 var b2; | 12 var b2; |
| 13 var a0; |
13 var a1; | 14 var a1; |
14 var a2; | 15 var a2; |
15 | 16 |
16 if (freq == 1) { | 17 if (freq == 1) { |
17 // The formula below works, except for roundoff. When freq = 1, | 18 // The formula below works, except for roundoff. When freq = 1, |
18 // the filter is just a wire, so hardwire the coefficients. | 19 // the filter is just a wire, so hardwire the coefficients. |
19 b0 = 1; | 20 b0 = 1; |
20 b1 = 0; | 21 b1 = 0; |
21 b2 = 0; | 22 b2 = 0; |
| 23 a0 = 1; |
22 a1 = 0; | 24 a1 = 0; |
23 a2 = 0; | 25 a2 = 0; |
24 } else { | 26 } else { |
25 var g = Math.pow(10, q / 20); | |
26 var d = Math.sqrt((4 - Math.sqrt(16 - 16 / (g * g))) / 2); | |
27 var theta = Math.PI * freq; | 27 var theta = Math.PI * freq; |
28 var sn = d * Math.sin(theta) / 2; | 28 var alpha = Math.sin(theta) / (2 * Math.pow(10, q / 20)); |
29 var beta = 0.5 * (1 - sn) / (1 + sn); | 29 var cosw = Math.cos(theta); |
30 var gamma = (0.5 + beta) * Math.cos(theta); | 30 var beta = (1 - cosw) / 2; |
31 var alpha = 0.25 * (0.5 + beta - gamma); | |
32 | 31 |
33 b0 = 2 * alpha; | 32 b0 = beta; |
34 b1 = 4 * alpha; | 33 b1 = 2 * beta; |
35 b2 = 2 * alpha; | 34 b2 = beta; |
36 a1 = 2 * (-gamma); | 35 a0 = 1 + alpha; |
37 a2 = 2 * beta; | 36 a1 = -2 * cosw; |
| 37 a2 = 1 - alpha; |
38 } | 38 } |
39 | 39 |
40 return {b0 : b0, b1 : b1, b2 : b2, a1 : a1, a2 : a2}; | 40 return normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2); |
41 } | 41 } |
42 | 42 |
43 function createHighpassFilter(freq, q, gain) { | 43 function createHighpassFilter(freq, q, gain) { |
44 var b0; | 44 var b0; |
45 var b1; | 45 var b1; |
46 var b2; | 46 var b2; |
| 47 var a0; |
47 var a1; | 48 var a1; |
48 var a2; | 49 var a2; |
49 | 50 |
50 if (freq == 1) { | 51 if (freq == 1) { |
51 // The filter is 0 | 52 // The filter is 0 |
52 b0 = 0; | 53 b0 = 0; |
53 b1 = 0; | 54 b1 = 0; |
54 b2 = 0; | 55 b2 = 0; |
| 56 a0 = 1; |
55 a1 = 0; | 57 a1 = 0; |
56 a2 = 0; | 58 a2 = 0; |
57 } else if (freq == 0) { | 59 } else if (freq == 0) { |
58 // The filter is 1. Computation of coefficients below is ok, but | 60 // The filter is 1. Computation of coefficients below is ok, but |
59 // there's a pole at 1 and a zero at 1, so round-off could make | 61 // there's a pole at 1 and a zero at 1, so round-off could make |
60 // the filter unstable. | 62 // the filter unstable. |
61 b0 = 1; | 63 b0 = 1; |
62 b1 = 0; | 64 b1 = 0; |
63 b2 = 0; | 65 b2 = 0; |
| 66 a0 = 1; |
64 a1 = 0; | 67 a1 = 0; |
65 a2 = 0; | 68 a2 = 0; |
66 } else { | 69 } else { |
67 var g = Math.pow(10, q / 20); | |
68 var d = Math.sqrt((4 - Math.sqrt(16 - 16 / (g * g))) / 2); | |
69 var theta = Math.PI * freq; | 70 var theta = Math.PI * freq; |
70 var sn = d * Math.sin(theta) / 2; | 71 var alpha = Math.sin(theta) / (2 * Math.pow(10, q / 20)); |
71 var beta = 0.5 * (1 - sn) / (1 + sn); | 72 var cosw = Math.cos(theta); |
72 var gamma = (0.5 + beta) * Math.cos(theta); | 73 var beta = (1 + cosw) / 2; |
73 var alpha = 0.25 * (0.5 + beta + gamma); | |
74 | 74 |
75 b0 = 2 * alpha; | 75 b0 = beta; |
76 b1 = -4 * alpha; | 76 b1 = -2 * beta; |
77 b2 = 2 * alpha; | 77 b2 = beta; |
78 a1 = 2 * (-gamma); | 78 a0 = 1 + alpha; |
79 a2 = 2 * beta; | 79 a1 = -2 * cosw; |
| 80 a2 = 1 - alpha; |
80 } | 81 } |
81 | 82 |
82 return {b0 : b0, b1 : b1, b2 : b2, a1 : a1, a2 : a2}; | 83 return normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2); |
83 } | 84 } |
84 | 85 |
85 function normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2) { | 86 function normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2) { |
86 var scale = 1 / a0; | 87 var scale = 1 / a0; |
87 | 88 |
88 return {b0 : b0 * scale, | 89 return {b0 : b0 * scale, |
89 b1 : b1 * scale, | 90 b1 : b1 * scale, |
90 b2 : b2 * scale, | 91 b2 : b2 * scale, |
91 a1 : a1 * scale, | 92 a1 : a1 * scale, |
92 a2 : a2 * scale}; | 93 a2 : a2 * scale}; |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 "bandpass": "Bandpass filter", | 360 "bandpass": "Bandpass filter", |
360 "lowshelf": "Lowshelf filter", | 361 "lowshelf": "Lowshelf filter", |
361 "highshelf": "Highshelf filter", | 362 "highshelf": "Highshelf filter", |
362 "peaking": "Peaking filter", | 363 "peaking": "Peaking filter", |
363 "notch": "Notch filter", | 364 "notch": "Notch filter", |
364 "allpass": "Allpass filter"}; | 365 "allpass": "Allpass filter"}; |
365 | 366 |
366 function createFilter(filterType, freq, q, gain) { | 367 function createFilter(filterType, freq, q, gain) { |
367 return filterCreatorFunction[filterType](freq, q, gain); | 368 return filterCreatorFunction[filterType](freq, q, gain); |
368 } | 369 } |
OLD | NEW |