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/GainNode.h"
     30 
     31 #include "core/platform/audio/AudioBus.h"
     32 #include "modules/webaudio/AudioNodeInput.h"
     33 #include "modules/webaudio/AudioNodeOutput.h"
     34 
     35 namespace WebCore {
     36 
     37 GainNode::GainNode(AudioContext* context, float sampleRate)
     38     : AudioNode(context, sampleRate)
     39     , m_lastGain(1.0)
     40     , m_sampleAccurateGainValues(AudioNode::ProcessingSizeInFrames) // FIXME: can probably share temp buffer in context
     41 {
     42     ScriptWrappable::init(this);
     43     m_gain = AudioParam::create(context, "gain", 1.0, 0.0, 1.0);
     44 
     45     addInput(adoptPtr(new AudioNodeInput(this)));
     46     addOutput(adoptPtr(new AudioNodeOutput(this, 1)));
     47 
     48     setNodeType(NodeTypeGain);
     49 
     50     initialize();
     51 }
     52 
     53 void GainNode::process(size_t framesToProcess)
     54 {
     55     // FIXME: for some cases there is a nice optimization to avoid processing here, and let the gain change
     56     // happen in the summing junction input of the AudioNode we're connected to.
     57     // Then we can avoid all of the following:
     58 
     59     AudioBus* outputBus = output(0)->bus();
     60     ASSERT(outputBus);
     61 
     62     if (!isInitialized() || !input(0)->isConnected())
     63         outputBus->zero();
     64     else {
     65         AudioBus* inputBus = input(0)->bus();
     66 
     67         if (gain()->hasSampleAccurateValues()) {
     68             // Apply sample-accurate gain scaling for precise envelopes, grain windows, etc.
     69             ASSERT(framesToProcess <= m_sampleAccurateGainValues.size());
     70             if (framesToProcess <= m_sampleAccurateGainValues.size()) {
     71                 float* gainValues = m_sampleAccurateGainValues.data();
     72                 gain()->calculateSampleAccurateValues(gainValues, framesToProcess);
     73                 outputBus->copyWithSampleAccurateGainValuesFrom(*inputBus, gainValues, framesToProcess);
     74             }
     75         } else {
     76             // Apply the gain with de-zippering into the output bus.
     77             outputBus->copyWithGainFrom(*inputBus, &m_lastGain, gain()->value());
     78         }
     79     }
     80 }
     81 
     82 void GainNode::reset()
     83 {
     84     // Snap directly to desired gain.
     85     m_lastGain = gain()->value();
     86 }
     87 
     88 // FIXME: this can go away when we do mixing with gain directly in summing junction of AudioNodeInput
     89 //
     90 // As soon as we know the channel count of our input, we can lazily initialize.
     91 // Sometimes this may be called more than once with different channel counts, in which case we must safely
     92 // uninitialize and then re-initialize with the new channel count.
     93 void GainNode::checkNumberOfChannelsForInput(AudioNodeInput* input)
     94 {
     95     ASSERT(context()->isAudioThread() && context()->isGraphOwner());
     96 
     97     ASSERT(input && input == this->input(0));
     98     if (input != this->input(0))
     99         return;
    100 
    101     unsigned numberOfChannels = input->numberOfChannels();
    102 
    103     if (isInitialized() && numberOfChannels != output(0)->numberOfChannels()) {
    104         // We're already initialized but the channel count has changed.
    105         uninitialize();
    106     }
    107 
    108     if (!isInitialized()) {
    109         // This will propagate the channel count to any nodes connected further downstream in the graph.
    110         output(0)->setNumberOfChannels(numberOfChannels);
    111         initialize();
    112     }
    113 
    114     AudioNode::checkNumberOfChannelsForInput(input);
    115 }
    116 
    117 } // namespace WebCore
    118 
    119 #endif // ENABLE(WEB_AUDIO)
    120