Chromium Code Reviews| 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 |