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/AudioBasicProcessorNode.h" 30 31#include "platform/audio/AudioBus.h" 32#include "platform/audio/AudioProcessor.h" 33#include "modules/webaudio/AudioContext.h" 34#include "modules/webaudio/AudioNodeInput.h" 35#include "modules/webaudio/AudioNodeOutput.h" 36 37namespace blink { 38 39AudioBasicProcessorNode::AudioBasicProcessorNode(AudioContext* context, float sampleRate) 40 : AudioNode(context, sampleRate) 41{ 42 addInput(); 43 addOutput(AudioNodeOutput::create(this, 1)); 44 45 // The subclass must create m_processor. 46} 47 48AudioBasicProcessorNode::~AudioBasicProcessorNode() 49{ 50 ASSERT(!isInitialized()); 51} 52 53void AudioBasicProcessorNode::trace(Visitor* visitor) 54{ 55 visitor->trace(m_processor); 56 AudioNode::trace(visitor); 57} 58 59void AudioBasicProcessorNode::dispose() 60{ 61 uninitialize(); 62 AudioNode::dispose(); 63} 64 65void AudioBasicProcessorNode::initialize() 66{ 67 if (isInitialized()) 68 return; 69 70 ASSERT(processor()); 71 processor()->initialize(); 72 73 AudioNode::initialize(); 74} 75 76void AudioBasicProcessorNode::uninitialize() 77{ 78 if (!isInitialized()) 79 return; 80 81 ASSERT(processor()); 82 processor()->uninitialize(); 83 84 AudioNode::uninitialize(); 85} 86 87void AudioBasicProcessorNode::process(size_t framesToProcess) 88{ 89 AudioBus* destinationBus = output(0)->bus(); 90 91 if (!isInitialized() || !processor() || processor()->numberOfChannels() != numberOfChannels()) 92 destinationBus->zero(); 93 else { 94 AudioBus* sourceBus = input(0)->bus(); 95 96 // FIXME: if we take "tail time" into account, then we can avoid calling processor()->process() once the tail dies down. 97 if (!input(0)->isConnected()) 98 sourceBus->zero(); 99 100 processor()->process(sourceBus, destinationBus, framesToProcess); 101 } 102} 103 104// Nice optimization in the very common case allowing for "in-place" processing 105void AudioBasicProcessorNode::pullInputs(size_t framesToProcess) 106{ 107 // Render input stream - suggest to the input to render directly into output bus for in-place processing in process() if possible. 108 input(0)->pull(output(0)->bus(), framesToProcess); 109} 110 111// As soon as we know the channel count of our input, we can lazily initialize. 112// Sometimes this may be called more than once with different channel counts, in which case we must safely 113// uninitialize and then re-initialize with the new channel count. 114void AudioBasicProcessorNode::checkNumberOfChannelsForInput(AudioNodeInput* input) 115{ 116 ASSERT(context()->isAudioThread() && context()->isGraphOwner()); 117 118 ASSERT(input == this->input(0)); 119 if (input != this->input(0)) 120 return; 121 122 ASSERT(processor()); 123 if (!processor()) 124 return; 125 126 unsigned numberOfChannels = input->numberOfChannels(); 127 128 if (isInitialized() && numberOfChannels != output(0)->numberOfChannels()) { 129 // We're already initialized but the channel count has changed. 130 uninitialize(); 131 } 132 133 if (!isInitialized()) { 134 // This will propagate the channel count to any nodes connected further down the chain... 135 output(0)->setNumberOfChannels(numberOfChannels); 136 137 // Re-initialize the processor with the new channel count. 138 processor()->setNumberOfChannels(numberOfChannels); 139 initialize(); 140 } 141 142 AudioNode::checkNumberOfChannelsForInput(input); 143} 144 145unsigned AudioBasicProcessorNode::numberOfChannels() 146{ 147 return output(0)->numberOfChannels(); 148} 149 150double AudioBasicProcessorNode::tailTime() const 151{ 152 return m_processor->tailTime(); 153} 154 155double AudioBasicProcessorNode::latencyTime() const 156{ 157 return m_processor->latencyTime(); 158} 159 160} // namespace blink 161 162#endif // ENABLE(WEB_AUDIO) 163