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 biquad object here is not the same as the one being processed bec ause a new biquad is | |
Ken Russell (switch to Gerrit)
2014/06/30 19:09:54
Please point out it's actually both the BiquadDSPK
Raymond Toy
2014/06/30 20:45:40
Done.
| |
164 // created in BiquadProcessor::getFrequencyResponse. | |
165 MutexLocker processLocker(m_processLock); | |
166 | |
167 cutoffFrequency = biquadProcessor()->parameter1()->value(); | |
168 Q = biquadProcessor()->parameter2()->value(); | |
169 gain = biquadProcessor()->parameter3()->value(); | |
170 detune = biquadProcessor()->parameter4()->value(); | |
171 } | |
172 | |
173 updateCoefficients(cutoffFrequency, Q, gain, detune); | |
Ken Russell (switch to Gerrit)
2014/06/30 17:48:55
Does this call to updateCoefficients need to be co
Raymond Toy
2014/06/30 18:06:11
It shouldn't be needed because updateCoefficients
Ken Russell (switch to Gerrit)
2014/06/30 18:26:38
Both BiquadDSPKernel::getFrequencyResponse and Biq
Raymond Toy
2014/06/30 18:44:51
They are different m_biquad objects. The m_biquad
Ken Russell (switch to Gerrit)
2014/06/30 19:09:54
It's not only different m_biquad (Biquad) objects,
Raymond Toy
2014/06/30 20:45:40
Clarified this in the comments.
Yes, it shouldn't
| |
151 | 174 |
152 m_biquad.getFrequencyResponse(nFrequencies, frequency.data(), magResponse, p haseResponse); | 175 m_biquad.getFrequencyResponse(nFrequencies, frequency.data(), magResponse, p haseResponse); |
153 } | 176 } |
154 | 177 |
155 double BiquadDSPKernel::tailTime() const | 178 double BiquadDSPKernel::tailTime() const |
156 { | 179 { |
157 return MaxBiquadDelayTime; | 180 return MaxBiquadDelayTime; |
158 } | 181 } |
159 | 182 |
160 double BiquadDSPKernel::latencyTime() const | 183 double BiquadDSPKernel::latencyTime() const |
161 { | 184 { |
162 return 0; | 185 return 0; |
163 } | 186 } |
164 | 187 |
165 } // namespace WebCore | 188 } // namespace WebCore |
166 | 189 |
167 #endif // ENABLE(WEB_AUDIO) | 190 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |