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