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 37 namespace blink { 38 39 AudioBasicProcessorNode::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 48 AudioBasicProcessorNode::~AudioBasicProcessorNode() 49 { 50 ASSERT(!isInitialized()); 51 } 52 53 void AudioBasicProcessorNode::trace(Visitor* visitor) 54 { 55 visitor->trace(m_processor); 56 AudioNode::trace(visitor); 57 } 58 59 void AudioBasicProcessorNode::dispose() 60 { 61 uninitialize(); 62 AudioNode::dispose(); 63 } 64 65 void AudioBasicProcessorNode::initialize() 66 { 67 if (isInitialized()) 68 return; 69 70 ASSERT(processor()); 71 processor()->initialize(); 72 73 AudioNode::initialize(); 74 } 75 76 void AudioBasicProcessorNode::uninitialize() 77 { 78 if (!isInitialized()) 79 return; 80 81 ASSERT(processor()); 82 processor()->uninitialize(); 83 84 AudioNode::uninitialize(); 85 } 86 87 void 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 105 void 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. 114 void 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 145 unsigned AudioBasicProcessorNode::numberOfChannels() 146 { 147 return output(0)->numberOfChannels(); 148 } 149 150 double AudioBasicProcessorNode::tailTime() const 151 { 152 return m_processor->tailTime(); 153 } 154 155 double AudioBasicProcessorNode::latencyTime() const 156 { 157 return m_processor->latencyTime(); 158 } 159 160 } // namespace blink 161 162 #endif // ENABLE(WEB_AUDIO) 163