1 /* 2 * Copyright (C) 2010, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include "config.h" 26 27 #if ENABLE(WEB_AUDIO) 28 29 #include "modules/webaudio/BiquadDSPKernel.h" 30 31 #include "core/platform/FloatConversion.h" 32 #include "modules/webaudio/BiquadProcessor.h" 33 #include <limits.h> 34 #include "wtf/Vector.h" 35 36 namespace WebCore { 37 38 // FIXME: As a recursive linear filter, depending on its parameters, a biquad filter can have 39 // an infinite tailTime. In practice, Biquad filters do not usually (except for very high resonance values) 40 // have a tailTime of longer than approx. 200ms. This value could possibly be calculated based on the 41 // settings of the Biquad. 42 static const double MaxBiquadDelayTime = 0.2; 43 44 void BiquadDSPKernel::updateCoefficientsIfNecessary(bool useSmoothing, bool forceUpdate) 45 { 46 if (forceUpdate || biquadProcessor()->filterCoefficientsDirty()) { 47 double value1; 48 double value2; 49 double gain; 50 double detune; // in Cents 51 52 if (biquadProcessor()->hasSampleAccurateValues()) { 53 value1 = biquadProcessor()->parameter1()->finalValue(); 54 value2 = biquadProcessor()->parameter2()->finalValue(); 55 gain = biquadProcessor()->parameter3()->finalValue(); 56 detune = biquadProcessor()->parameter4()->finalValue(); 57 } else if (useSmoothing) { 58 value1 = biquadProcessor()->parameter1()->smoothedValue(); 59 value2 = biquadProcessor()->parameter2()->smoothedValue(); 60 gain = biquadProcessor()->parameter3()->smoothedValue(); 61 detune = biquadProcessor()->parameter4()->smoothedValue(); 62 } else { 63 value1 = biquadProcessor()->parameter1()->value(); 64 value2 = biquadProcessor()->parameter2()->value(); 65 gain = biquadProcessor()->parameter3()->value(); 66 detune = biquadProcessor()->parameter4()->value(); 67 } 68 69 // Convert from Hertz to normalized frequency 0 -> 1. 70 double nyquist = this->nyquist(); 71 double normalizedFrequency = value1 / 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 type of filter. 78 switch (biquadProcessor()->type()) { 79 case BiquadProcessor::LowPass: 80 m_biquad.setLowpassParams(normalizedFrequency, value2); 81 break; 82 83 case BiquadProcessor::HighPass: 84 m_biquad.setHighpassParams(normalizedFrequency, value2); 85 break; 86 87 case BiquadProcessor::BandPass: 88 m_biquad.setBandpassParams(normalizedFrequency, value2); 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, value2, gain); 101 break; 102 103 case BiquadProcessor::Notch: 104 m_biquad.setNotchParams(normalizedFrequency, value2); 105 break; 106 107 case BiquadProcessor::Allpass: 108 m_biquad.setAllpassParams(normalizedFrequency, value2); 109 break; 110 } 111 } 112 } 113 114 void BiquadDSPKernel::process(const float* source, float* destination, size_t framesToProcess) 115 { 116 ASSERT(source && destination && biquadProcessor()); 117 118 // Recompute filter coefficients if any of the parameters have changed. 119 // FIXME: as an optimization, implement a way that a Biquad object can simply copy its internal filter coefficients from another Biquad object. 120 // Then re-factor this code to only run for the first BiquadDSPKernel of each BiquadProcessor. 121 122 updateCoefficientsIfNecessary(true, false); 123 124 m_biquad.process(source, destination, framesToProcess); 125 } 126 127 void BiquadDSPKernel::getFrequencyResponse(int nFrequencies, 128 const float* frequencyHz, 129 float* magResponse, 130 float* phaseResponse) 131 { 132 bool isGood = nFrequencies > 0 && frequencyHz && magResponse && phaseResponse; 133 ASSERT(isGood); 134 if (!isGood) 135 return; 136 137 Vector<float> frequency(nFrequencies); 138 139 double nyquist = this->nyquist(); 140 141 // Convert from frequency in Hz to normalized frequency (0 -> 1), 142 // with 1 equal to the Nyquist frequency. 143 for (int k = 0; k < nFrequencies; ++k) 144 frequency[k] = narrowPrecisionToFloat(frequencyHz[k] / nyquist); 145 146 // We want to get the final values of the coefficients and compute 147 // the response from that instead of some intermediate smoothed 148 // set. Forcefully update the coefficients even if they are not 149 // dirty. 150 151 updateCoefficientsIfNecessary(false, true); 152 153 m_biquad.getFrequencyResponse(nFrequencies, frequency.data(), magResponse, phaseResponse); 154 } 155 156 double BiquadDSPKernel::tailTime() const 157 { 158 return MaxBiquadDelayTime; 159 } 160 161 double BiquadDSPKernel::latencyTime() const 162 { 163 return 0; 164 } 165 166 } // namespace WebCore 167 168 #endif // ENABLE(WEB_AUDIO) 169