| 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 |