Home | History | Annotate | Download | only in webaudio
      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/BiquadProcessor.h"
     30 
     31 #include "modules/webaudio/BiquadDSPKernel.h"
     32 
     33 namespace WebCore {
     34 
     35 BiquadProcessor::BiquadProcessor(AudioContext* context, float sampleRate, size_t numberOfChannels, bool autoInitialize)
     36     : AudioDSPKernelProcessor(sampleRate, numberOfChannels)
     37     , m_type(LowPass)
     38     , m_parameter1(nullptr)
     39     , m_parameter2(nullptr)
     40     , m_parameter3(nullptr)
     41     , m_parameter4(nullptr)
     42     , m_filterCoefficientsDirty(true)
     43     , m_hasSampleAccurateValues(false)
     44 {
     45     double nyquist = 0.5 * this->sampleRate();
     46 
     47     // Create parameters for BiquadFilterNode.
     48     m_parameter1 = AudioParam::create(context, "frequency", 350.0, 10.0, nyquist);
     49     m_parameter2 = AudioParam::create(context, "Q", 1, 0.0001, 1000.0);
     50     m_parameter3 = AudioParam::create(context, "gain", 0.0, -40, 40);
     51     m_parameter4 = AudioParam::create(context, "detune", 0.0, -4800, 4800);
     52 
     53     if (autoInitialize)
     54         initialize();
     55 }
     56 
     57 BiquadProcessor::~BiquadProcessor()
     58 {
     59     if (isInitialized())
     60         uninitialize();
     61 }
     62 
     63 PassOwnPtr<AudioDSPKernel> BiquadProcessor::createKernel()
     64 {
     65     return adoptPtr(new BiquadDSPKernel(this));
     66 }
     67 
     68 void BiquadProcessor::checkForDirtyCoefficients()
     69 {
     70     // Deal with smoothing / de-zippering. Start out assuming filter parameters are not changing.
     71 
     72     // The BiquadDSPKernel objects rely on this value to see if they need to re-compute their internal filter coefficients.
     73     m_filterCoefficientsDirty = false;
     74     m_hasSampleAccurateValues = false;
     75 
     76     if (m_parameter1->hasSampleAccurateValues() || m_parameter2->hasSampleAccurateValues() || m_parameter3->hasSampleAccurateValues() || m_parameter4->hasSampleAccurateValues()) {
     77         m_filterCoefficientsDirty = true;
     78         m_hasSampleAccurateValues = true;
     79     } else {
     80         if (m_hasJustReset) {
     81             // Snap to exact values first time after reset, then smooth for subsequent changes.
     82             m_parameter1->resetSmoothedValue();
     83             m_parameter2->resetSmoothedValue();
     84             m_parameter3->resetSmoothedValue();
     85             m_parameter4->resetSmoothedValue();
     86             m_filterCoefficientsDirty = true;
     87             m_hasJustReset = false;
     88         } else {
     89             // Smooth all of the filter parameters. If they haven't yet converged to their target value then mark coefficients as dirty.
     90             bool isStable1 = m_parameter1->smooth();
     91             bool isStable2 = m_parameter2->smooth();
     92             bool isStable3 = m_parameter3->smooth();
     93             bool isStable4 = m_parameter4->smooth();
     94             if (!(isStable1 && isStable2 && isStable3 && isStable4))
     95                 m_filterCoefficientsDirty = true;
     96         }
     97     }
     98 }
     99 
    100 void BiquadProcessor::process(const AudioBus* source, AudioBus* destination, size_t framesToProcess)
    101 {
    102     if (!isInitialized()) {
    103         destination->zero();
    104         return;
    105     }
    106 
    107     checkForDirtyCoefficients();
    108 
    109     // For each channel of our input, process using the corresponding BiquadDSPKernel into the output channel.
    110     for (unsigned i = 0; i < m_kernels.size(); ++i)
    111         m_kernels[i]->process(source->channel(i)->data(), destination->channel(i)->mutableData(), framesToProcess);
    112 }
    113 
    114 void BiquadProcessor::setType(FilterType type)
    115 {
    116     if (type != m_type) {
    117         m_type = type;
    118         reset(); // The filter state must be reset only if the type has changed.
    119     }
    120 }
    121 
    122 void BiquadProcessor::getFrequencyResponse(int nFrequencies,
    123                                            const float* frequencyHz,
    124                                            float* magResponse,
    125                                            float* phaseResponse)
    126 {
    127     // Compute the frequency response on a separate temporary kernel
    128     // to avoid interfering with the processing running in the audio
    129     // thread on the main kernels.
    130 
    131     OwnPtr<BiquadDSPKernel> responseKernel = adoptPtr(new BiquadDSPKernel(this));
    132 
    133     responseKernel->getFrequencyResponse(nFrequencies, frequencyHz, magResponse, phaseResponse);
    134 }
    135 
    136 } // namespace WebCore
    137 
    138 #endif // ENABLE(WEB_AUDIO)
    139