LowPass2FilterNode::LowPass2FilterNode(AudioContext* context, float sampleRate) : AudioBasicProcessorNode(context, sampleRate) { m_processor = adoptPtr(new BiquadProcessor(BiquadProcessor::LowPass, sampleRate, 1, false)); biquadProcessor()->parameter1()->setContext(context); biquadProcessor()->parameter2()->setContext(context); biquadProcessor()->parameter3()->setContext(context); setNodeType(NodeTypeLowPass2Filter); }
BiquadFilterNode::BiquadFilterNode(AudioContext* context, double sampleRate) : AudioBasicProcessorNode(context, sampleRate) { // Initially setup as lowpass filter. m_processor = adoptPtr(new BiquadProcessor(BiquadProcessor::LowPass, sampleRate, 1, false)); biquadProcessor()->parameter1()->setContext(context); biquadProcessor()->parameter2()->setContext(context); biquadProcessor()->parameter3()->setContext(context); setType(NodeTypeBiquadFilter); }
void BiquadDSPKernel::updateCoefficientsIfNecessary(bool useSmoothing, bool forceUpdate) { if (forceUpdate || biquadProcessor()->filterCoefficientsDirty()) { double value1; double value2; double gain; if (useSmoothing) { value1 = biquadProcessor()->parameter1()->smoothedValue(); value2 = biquadProcessor()->parameter2()->smoothedValue(); gain = biquadProcessor()->parameter3()->smoothedValue(); } else { value1 = biquadProcessor()->parameter1()->value(); value2 = biquadProcessor()->parameter2()->value(); gain = biquadProcessor()->parameter3()->value(); } // Convert from Hertz to normalized frequency 0 -> 1. double nyquist = this->nyquist(); double normalizedFrequency = value1 / nyquist; // Configure the biquad with the new filter parameters for the appropriate type of filter. switch (biquadProcessor()->type()) { case BiquadProcessor::LowPass: m_biquad.setLowpassParams(normalizedFrequency, value2); break; case BiquadProcessor::HighPass: m_biquad.setHighpassParams(normalizedFrequency, value2); break; case BiquadProcessor::BandPass: m_biquad.setBandpassParams(normalizedFrequency, value2); break; case BiquadProcessor::LowShelf: m_biquad.setLowShelfParams(normalizedFrequency, gain); break; case BiquadProcessor::HighShelf: m_biquad.setHighShelfParams(normalizedFrequency, gain); break; case BiquadProcessor::Peaking: m_biquad.setPeakingParams(normalizedFrequency, value2, gain); break; case BiquadProcessor::Notch: m_biquad.setNotchParams(normalizedFrequency, value2); break; case BiquadProcessor::Allpass: m_biquad.setAllpassParams(normalizedFrequency, value2); break; } } }
bool BiquadFilterNode::setType(unsigned type) { if (type > BiquadProcessor::Allpass) return false; biquadProcessor()->setType(static_cast<BiquadProcessor::FilterType>(type)); return true; }
void BiquadDSPKernel::getFrequencyResponse(int nFrequencies, const float* frequencyHz, float* magResponse, float* phaseResponse) { bool isGood = nFrequencies > 0 && frequencyHz && magResponse && phaseResponse; ASSERT(isGood); if (!isGood) return; Vector<float> frequency(nFrequencies); double nyquist = this->nyquist(); // Convert from frequency in Hz to normalized frequency (0 -> 1), // with 1 equal to the Nyquist frequency. for (int k = 0; k < nFrequencies; ++k) frequency[k] = narrowPrecisionToFloat(frequencyHz[k] / nyquist); double cutoffFrequency; double Q; double gain; double detune; // in Cents { // Get a copy of the current biquad filter coefficients so we can update the biquad with // these values. We need to synchronize with process() to prevent process() from updating // the filter coefficients while we're trying to access them. The process will update it // next time around. // // The BiquadDSPKernel object here (along with it's Biquad object) is for querying the // frequency response and is NOT the same as the one in process() which is used for // performing the actual filtering. This one is is created in // BiquadProcessor::getFrequencyResponse for this purpose. Both, however, point to the same // BiquadProcessor object. // // FIXME: Simplify this: crbug.com/390266 MutexLocker processLocker(m_processLock); cutoffFrequency = biquadProcessor()->parameter1().value(); Q = biquadProcessor()->parameter2().value(); gain = biquadProcessor()->parameter3().value(); detune = biquadProcessor()->parameter4().value(); } updateCoefficients(cutoffFrequency, Q, gain, detune); m_biquad.getFrequencyResponse(nFrequencies, frequency.data(), magResponse, phaseResponse); }
void BiquadFilterNode::setType(unsigned short type, ExceptionCode& ec) { if (type > BiquadProcessor::Allpass) { ec = NOT_SUPPORTED_ERR; return; } biquadProcessor()->setType(static_cast<BiquadProcessor::FilterType>(type)); }
void BiquadFilterNode::getFrequencyResponse(const RefPtr<Float32Array>& frequencyHz, const RefPtr<Float32Array>& magResponse, const RefPtr<Float32Array>& phaseResponse) { if (!frequencyHz || !magResponse || !phaseResponse) return; int n = std::min(frequencyHz->length(), std::min(magResponse->length(), phaseResponse->length())); if (n) biquadProcessor()->getFrequencyResponse(n, frequencyHz->data(), magResponse->data(), phaseResponse->data()); }
void BiquadDSPKernel::process(const float* source, float* destination, size_t framesToProcess) { ASSERT(source && destination && biquadProcessor()); // Recompute filter coefficients if any of the parameters have changed. // FIXME: as an optimization, implement a way that a Biquad object can simply copy its internal filter coefficients from another Biquad object. // Then re-factor this code to only run for the first BiquadDSPKernel of each BiquadProcessor. updateCoefficientsIfNecessary(true, false); m_biquad.process(source, destination, framesToProcess); }
void BiquadDSPKernel::process(const float* source, float* destination, size_t framesToProcess) { ASSERT(source && destination && biquadProcessor()); // Recompute filter coefficients if any of the parameters have changed. // FIXME: as an optimization, implement a way that a Biquad object can simply copy its internal filter coefficients from another Biquad object. // Then re-factor this code to only run for the first BiquadDSPKernel of each BiquadProcessor. if (biquadProcessor()->filterCoefficientsDirty()) { double value1 = biquadProcessor()->parameter1()->smoothedValue(); double value2 = biquadProcessor()->parameter2()->smoothedValue(); // Convert from Hertz to normalized frequency 0 -> 1. double nyquist = this->nyquist(); double normalizedValue1 = value1 / nyquist; // Configure the biquad with the new filter parameters for the appropriate type of filter. switch (biquadProcessor()->type()) { case BiquadProcessor::LowPass2: m_biquad.setLowpassParams(normalizedValue1, value2); break; case BiquadProcessor::HighPass2: m_biquad.setHighpassParams(normalizedValue1, value2); break; case BiquadProcessor::LowShelf: m_biquad.setLowShelfParams(normalizedValue1, value2); break; // FIXME: add other biquad filter types... case BiquadProcessor::Peaking: case BiquadProcessor::Allpass: case BiquadProcessor::HighShelf: break; } } m_biquad.process(source, destination, framesToProcess); }
void BiquadDSPKernel::updateCoefficientsIfNecessary() { if (biquadProcessor()->filterCoefficientsDirty()) { double cutoffFrequency; double Q; double gain; double detune; // in Cents if (biquadProcessor()->hasSampleAccurateValues()) { cutoffFrequency = biquadProcessor()->parameter1().finalValue(); Q = biquadProcessor()->parameter2().finalValue(); gain = biquadProcessor()->parameter3().finalValue(); detune = biquadProcessor()->parameter4().finalValue(); } else { cutoffFrequency = biquadProcessor()->parameter1().smoothedValue(); Q = biquadProcessor()->parameter2().smoothedValue(); gain = biquadProcessor()->parameter3().smoothedValue(); detune = biquadProcessor()->parameter4().smoothedValue(); } updateCoefficients(cutoffFrequency, Q, gain, detune); } }
void BiquadDSPKernel::updateCoefficients(double cutoffFrequency, double Q, double gain, double detune) { // Convert from Hertz to normalized frequency 0 -> 1. double nyquist = this->nyquist(); double normalizedFrequency = cutoffFrequency / nyquist; // Offset frequency by detune. if (detune) normalizedFrequency *= pow(2, detune / 1200); // Configure the biquad with the new filter parameters for the appropriate type of filter. switch (biquadProcessor()->type()) { case BiquadProcessor::LowPass: m_biquad.setLowpassParams(normalizedFrequency, Q); break; case BiquadProcessor::HighPass: m_biquad.setHighpassParams(normalizedFrequency, Q); break; case BiquadProcessor::BandPass: m_biquad.setBandpassParams(normalizedFrequency, Q); break; case BiquadProcessor::LowShelf: m_biquad.setLowShelfParams(normalizedFrequency, gain); break; case BiquadProcessor::HighShelf: m_biquad.setHighShelfParams(normalizedFrequency, gain); break; case BiquadProcessor::Peaking: m_biquad.setPeakingParams(normalizedFrequency, Q, gain); break; case BiquadProcessor::Notch: m_biquad.setNotchParams(normalizedFrequency, Q); break; case BiquadProcessor::Allpass: m_biquad.setAllpassParams(normalizedFrequency, Q); break; } }
void BiquadDSPKernel::process(const float* source, float* destination, size_t framesToProcess) { ASSERT(source); ASSERT(destination); ASSERT(biquadProcessor()); // Recompute filter coefficients if any of the parameters have changed. // FIXME: as an optimization, implement a way that a Biquad object can simply copy its internal filter coefficients from another Biquad object. // Then re-factor this code to only run for the first BiquadDSPKernel of each BiquadProcessor. // The audio thread can't block on this lock; skip updating the coefficients for this block if // necessary. We'll get them the next time around. { MutexTryLocker tryLocker(m_processLock); if (tryLocker.locked()) updateCoefficientsIfNecessary(); } m_biquad.process(source, destination, framesToProcess); }
void BiquadFilterNode::setType(BiquadFilterType type) { biquadProcessor()->setType(type); }