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 "platform/FloatConversion.h" 32 #include <limits.h> 33 #include "wtf/Vector.h" 34 35 namespace WebCore { 36 37 // FIXME: As a recursive linear filter, depending on its parameters, a biquad filter can have 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 calculated based on the 40 // settings of the Biquad. 41 static const double MaxBiquadDelayTime = 0.2; 42 43 void BiquadDSPKernel::updateCoefficientsIfNecessary(bool useSmoothing, bool forceUpdate) 44 { 45 if (forceUpdate || biquadProcessor()->filterCoefficientsDirty()) { 46 double value1; 47 double value2; 48 double gain; 49 double detune; // in Cents 50 51 if (biquadProcessor()->hasSampleAccurateValues()) { 52 value1 = biquadProcessor()->parameter1()->finalValue(); 53 value2 = biquadProcessor()->parameter2()->finalValue(); 54 gain = biquadProcessor()->parameter3()->finalValue(); 55 detune = biquadProcessor()->parameter4()->finalValue(); 56 } else if (useSmoothing) { 57 value1 = biquadProcessor()->parameter1()->smoothedValue(); 58 value2 = biquadProcessor()->parameter2()->smoothedValue(); 59 gain = biquadProcessor()->parameter3()->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 } 67 68 // Convert from Hertz to normalized frequency 0 -> 1. 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 appropriate 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 } 111 } 112 113 void BiquadDSPKernel::process(const float* source, float* destination, size_t framesToProcess) 114 { 115 ASSERT(source && destination && biquadProcessor()); 116 117 // Recompute filter coefficients if any of the parameters have changed. 118 // FIXME: as an optimization, implement a way that a Biquad object can simply copy its internal filter coefficients from another Biquad object. 119 // Then re-factor this code to only run for the first BiquadDSPKernel of each BiquadProcessor. 120 121 updateCoefficientsIfNecessary(true, false); 122 123 m_biquad.process(source, destination, framesToProcess); 124 } 125 126 void BiquadDSPKernel::getFrequencyResponse(int nFrequencies, 127 const float* frequencyHz, 128 float* magResponse, 129 float* phaseResponse) 130 { 131 bool isGood = nFrequencies > 0 && frequencyHz && magResponse && phaseResponse; 132 ASSERT(isGood); 133 if (!isGood) 134 return; 135 136 Vector<float> frequency(nFrequencies); 137 138 double nyquist = this->nyquist(); 139 140 // Convert from frequency in Hz to normalized frequency (0 -> 1), 141 // with 1 equal to the Nyquist frequency. 142 for (int k = 0; k < nFrequencies; ++k) 143 frequency[k] = narrowPrecisionToFloat(frequencyHz[k] / nyquist); 144 145 // We want to get the final values of the coefficients and compute 146 // the response from that instead of some intermediate smoothed 147 // set. Forcefully update the coefficients even if they are not 148 // dirty. 149 150 updateCoefficientsIfNecessary(false, true); 151 152 m_biquad.getFrequencyResponse(nFrequencies, frequency.data(), magResponse, phaseResponse); 153 } 154 155 double BiquadDSPKernel::tailTime() const 156 { 157 return MaxBiquadDelayTime; 158 } 159 160 double BiquadDSPKernel::latencyTime() const 161 { 162 return 0; 163 } 164 165 } // namespace WebCore 166 167 #endif // ENABLE(WEB_AUDIO) 168