OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 22 matching lines...) Expand all Loading... |
33 #include "wtf/Vector.h" | 33 #include "wtf/Vector.h" |
34 | 34 |
35 namespace WebCore { | 35 namespace WebCore { |
36 | 36 |
37 // FIXME: As a recursive linear filter, depending on its parameters, a biquad fi
lter can have | 37 // FIXME: As a recursive linear filter, depending on its parameters, a biquad fi
lter can have |
38 // an infinite tailTime. In practice, Biquad filters do not usually (except for
very high resonance values) | 38 // an infinite tailTime. In practice, Biquad filters do not usually (except for
very high resonance values) |
39 // have a tailTime of longer than approx. 200ms. This value could possibly be ca
lculated based on the | 39 // have a tailTime of longer than approx. 200ms. This value could possibly be ca
lculated based on the |
40 // settings of the Biquad. | 40 // settings of the Biquad. |
41 static const double MaxBiquadDelayTime = 0.2; | 41 static const double MaxBiquadDelayTime = 0.2; |
42 | 42 |
43 void BiquadDSPKernel::updateCoefficientsIfNecessary(bool useSmoothing, bool forc
eUpdate) | 43 void BiquadDSPKernel::updateCoefficientsIfNecessary() |
44 { | 44 { |
45 if (forceUpdate || biquadProcessor()->filterCoefficientsDirty()) { | 45 if (biquadProcessor()->filterCoefficientsDirty()) { |
46 double value1; | 46 double cutoffFrequency; |
47 double value2; | 47 double Q; |
48 double gain; | 48 double gain; |
49 double detune; // in Cents | 49 double detune; // in Cents |
50 | 50 |
51 if (biquadProcessor()->hasSampleAccurateValues()) { | 51 if (biquadProcessor()->hasSampleAccurateValues()) { |
52 value1 = biquadProcessor()->parameter1()->finalValue(); | 52 cutoffFrequency = biquadProcessor()->parameter1()->finalValue(); |
53 value2 = biquadProcessor()->parameter2()->finalValue(); | 53 Q = biquadProcessor()->parameter2()->finalValue(); |
54 gain = biquadProcessor()->parameter3()->finalValue(); | 54 gain = biquadProcessor()->parameter3()->finalValue(); |
55 detune = biquadProcessor()->parameter4()->finalValue(); | 55 detune = biquadProcessor()->parameter4()->finalValue(); |
56 } else if (useSmoothing) { | 56 } else { |
57 value1 = biquadProcessor()->parameter1()->smoothedValue(); | 57 cutoffFrequency = biquadProcessor()->parameter1()->smoothedValue(); |
58 value2 = biquadProcessor()->parameter2()->smoothedValue(); | 58 Q = biquadProcessor()->parameter2()->smoothedValue(); |
59 gain = biquadProcessor()->parameter3()->smoothedValue(); | 59 gain = biquadProcessor()->parameter3()->smoothedValue(); |
60 detune = biquadProcessor()->parameter4()->smoothedValue(); | 60 detune = biquadProcessor()->parameter4()->smoothedValue(); |
61 } else { | |
62 value1 = biquadProcessor()->parameter1()->value(); | |
63 value2 = biquadProcessor()->parameter2()->value(); | |
64 gain = biquadProcessor()->parameter3()->value(); | |
65 detune = biquadProcessor()->parameter4()->value(); | |
66 } | 61 } |
67 | 62 |
68 // Convert from Hertz to normalized frequency 0 -> 1. | 63 updateCoefficients(cutoffFrequency, Q, gain, detune); |
69 double nyquist = this->nyquist(); | |
70 double normalizedFrequency = value1 / nyquist; | |
71 | |
72 // Offset frequency by detune. | |
73 if (detune) | |
74 normalizedFrequency *= pow(2, detune / 1200); | |
75 | |
76 // Configure the biquad with the new filter parameters for the appropria
te type of filter. | |
77 switch (biquadProcessor()->type()) { | |
78 case BiquadProcessor::LowPass: | |
79 m_biquad.setLowpassParams(normalizedFrequency, value2); | |
80 break; | |
81 | |
82 case BiquadProcessor::HighPass: | |
83 m_biquad.setHighpassParams(normalizedFrequency, value2); | |
84 break; | |
85 | |
86 case BiquadProcessor::BandPass: | |
87 m_biquad.setBandpassParams(normalizedFrequency, value2); | |
88 break; | |
89 | |
90 case BiquadProcessor::LowShelf: | |
91 m_biquad.setLowShelfParams(normalizedFrequency, gain); | |
92 break; | |
93 | |
94 case BiquadProcessor::HighShelf: | |
95 m_biquad.setHighShelfParams(normalizedFrequency, gain); | |
96 break; | |
97 | |
98 case BiquadProcessor::Peaking: | |
99 m_biquad.setPeakingParams(normalizedFrequency, value2, gain); | |
100 break; | |
101 | |
102 case BiquadProcessor::Notch: | |
103 m_biquad.setNotchParams(normalizedFrequency, value2); | |
104 break; | |
105 | |
106 case BiquadProcessor::Allpass: | |
107 m_biquad.setAllpassParams(normalizedFrequency, value2); | |
108 break; | |
109 } | |
110 } | 64 } |
111 } | 65 } |
112 | 66 |
| 67 void BiquadDSPKernel::updateCoefficients(double cutoffFrequency, double Q, doubl
e gain, double detune) |
| 68 { |
| 69 // Convert from Hertz to normalized frequency 0 -> 1. |
| 70 double nyquist = this->nyquist(); |
| 71 double normalizedFrequency = cutoffFrequency / nyquist; |
| 72 |
| 73 // Offset frequency by detune. |
| 74 if (detune) |
| 75 normalizedFrequency *= pow(2, detune / 1200); |
| 76 |
| 77 // Configure the biquad with the new filter parameters for the appropriate t
ype of filter. |
| 78 switch (biquadProcessor()->type()) { |
| 79 case BiquadProcessor::LowPass: |
| 80 m_biquad.setLowpassParams(normalizedFrequency, Q); |
| 81 break; |
| 82 |
| 83 case BiquadProcessor::HighPass: |
| 84 m_biquad.setHighpassParams(normalizedFrequency, Q); |
| 85 break; |
| 86 |
| 87 case BiquadProcessor::BandPass: |
| 88 m_biquad.setBandpassParams(normalizedFrequency, Q); |
| 89 break; |
| 90 |
| 91 case BiquadProcessor::LowShelf: |
| 92 m_biquad.setLowShelfParams(normalizedFrequency, gain); |
| 93 break; |
| 94 |
| 95 case BiquadProcessor::HighShelf: |
| 96 m_biquad.setHighShelfParams(normalizedFrequency, gain); |
| 97 break; |
| 98 |
| 99 case BiquadProcessor::Peaking: |
| 100 m_biquad.setPeakingParams(normalizedFrequency, Q, gain); |
| 101 break; |
| 102 |
| 103 case BiquadProcessor::Notch: |
| 104 m_biquad.setNotchParams(normalizedFrequency, Q); |
| 105 break; |
| 106 |
| 107 case BiquadProcessor::Allpass: |
| 108 m_biquad.setAllpassParams(normalizedFrequency, Q); |
| 109 break; |
| 110 } |
| 111 } |
| 112 |
113 void BiquadDSPKernel::process(const float* source, float* destination, size_t fr
amesToProcess) | 113 void BiquadDSPKernel::process(const float* source, float* destination, size_t fr
amesToProcess) |
114 { | 114 { |
115 ASSERT(source && destination && biquadProcessor()); | 115 ASSERT(source && destination && biquadProcessor()); |
116 | 116 |
117 // Recompute filter coefficients if any of the parameters have changed. | 117 // Recompute filter coefficients if any of the parameters have changed. |
118 // FIXME: as an optimization, implement a way that a Biquad object can simpl
y copy its internal filter coefficients from another Biquad object. | 118 // FIXME: as an optimization, implement a way that a Biquad object can simpl
y copy its internal filter coefficients from another Biquad object. |
119 // Then re-factor this code to only run for the first BiquadDSPKernel of eac
h BiquadProcessor. | 119 // Then re-factor this code to only run for the first BiquadDSPKernel of eac
h BiquadProcessor. |
120 | 120 |
121 updateCoefficientsIfNecessary(true, false); | 121 |
| 122 // The audio thread can't block on this lock; skip updating the coefficients
for this block if |
| 123 // necessary. We'll get them the next time around. |
| 124 { |
| 125 MutexTryLocker tryLocker(m_processLock); |
| 126 if (tryLocker.locked()) |
| 127 updateCoefficientsIfNecessary(); |
| 128 } |
122 | 129 |
123 m_biquad.process(source, destination, framesToProcess); | 130 m_biquad.process(source, destination, framesToProcess); |
124 } | 131 } |
125 | 132 |
126 void BiquadDSPKernel::getFrequencyResponse(int nFrequencies, | 133 void BiquadDSPKernel::getFrequencyResponse(int nFrequencies, |
127 const float* frequencyHz, | 134 const float* frequencyHz, |
128 float* magResponse, | 135 float* magResponse, |
129 float* phaseResponse) | 136 float* phaseResponse) |
130 { | 137 { |
131 bool isGood = nFrequencies > 0 && frequencyHz && magResponse && phaseRespons
e; | 138 bool isGood = nFrequencies > 0 && frequencyHz && magResponse && phaseRespons
e; |
132 ASSERT(isGood); | 139 ASSERT(isGood); |
133 if (!isGood) | 140 if (!isGood) |
134 return; | 141 return; |
135 | 142 |
136 Vector<float> frequency(nFrequencies); | 143 Vector<float> frequency(nFrequencies); |
137 | 144 |
138 double nyquist = this->nyquist(); | 145 double nyquist = this->nyquist(); |
139 | 146 |
140 // Convert from frequency in Hz to normalized frequency (0 -> 1), | 147 // Convert from frequency in Hz to normalized frequency (0 -> 1), |
141 // with 1 equal to the Nyquist frequency. | 148 // with 1 equal to the Nyquist frequency. |
142 for (int k = 0; k < nFrequencies; ++k) | 149 for (int k = 0; k < nFrequencies; ++k) |
143 frequency[k] = narrowPrecisionToFloat(frequencyHz[k] / nyquist); | 150 frequency[k] = narrowPrecisionToFloat(frequencyHz[k] / nyquist); |
144 | 151 |
145 // We want to get the final values of the coefficients and compute | 152 double cutoffFrequency; |
146 // the response from that instead of some intermediate smoothed | 153 double Q; |
147 // set. Forcefully update the coefficients even if they are not | 154 double gain; |
148 // dirty. | 155 double detune; // in Cents |
149 | 156 |
150 updateCoefficientsIfNecessary(false, true); | 157 { |
| 158 // Get a copy of the current biquad filter coefficients so we can update
the biquad with |
| 159 // these values. We need to synchronize with process() to prevent proces
s() from updating |
| 160 // the filter coefficients while we're trying to access them. The proces
s will update it |
| 161 // next time around. |
| 162 // |
| 163 // The BiquadDSPKernel object here (along with it's Biquad object) is fo
r querying the |
| 164 // frequency response and is NOT the same as the one in process() which
is used for |
| 165 // performing the actual filtering. This one is is created in |
| 166 // BiquadProcessor::getFrequencyResponse for this purpose. Both, however
, point to the same |
| 167 // BiquadProcessor object. |
| 168 // |
| 169 // FIXME: Simplify this: crbug.com/390266 |
| 170 MutexLocker processLocker(m_processLock); |
| 171 |
| 172 cutoffFrequency = biquadProcessor()->parameter1()->value(); |
| 173 Q = biquadProcessor()->parameter2()->value(); |
| 174 gain = biquadProcessor()->parameter3()->value(); |
| 175 detune = biquadProcessor()->parameter4()->value(); |
| 176 } |
| 177 |
| 178 updateCoefficients(cutoffFrequency, Q, gain, detune); |
151 | 179 |
152 m_biquad.getFrequencyResponse(nFrequencies, frequency.data(), magResponse, p
haseResponse); | 180 m_biquad.getFrequencyResponse(nFrequencies, frequency.data(), magResponse, p
haseResponse); |
153 } | 181 } |
154 | 182 |
155 double BiquadDSPKernel::tailTime() const | 183 double BiquadDSPKernel::tailTime() const |
156 { | 184 { |
157 return MaxBiquadDelayTime; | 185 return MaxBiquadDelayTime; |
158 } | 186 } |
159 | 187 |
160 double BiquadDSPKernel::latencyTime() const | 188 double BiquadDSPKernel::latencyTime() const |
161 { | 189 { |
162 return 0; | 190 return 0; |
163 } | 191 } |
164 | 192 |
165 } // namespace WebCore | 193 } // namespace WebCore |
166 | 194 |
167 #endif // ENABLE(WEB_AUDIO) | 195 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |