Non-unified build fixes, late September 2020 edition
[WebKit-https.git] / Source / WebCore / Modules / webaudio / GainNode.cpp
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 "GainNode.h"
30
31 #include "AudioBus.h"
32 #include "AudioNodeInput.h"
33 #include "AudioNodeOutput.h"
34 #include "AudioUtilities.h"
35 #include <wtf/IsoMallocInlines.h>
36
37 namespace WebCore {
38
39 WTF_MAKE_ISO_ALLOCATED_IMPL(GainNode);
40
41 ExceptionOr<Ref<GainNode>> GainNode::create(BaseAudioContext& context, const GainOptions& options)
42 {
43     if (context.isStopped())
44         return Exception { InvalidStateError };
45
46     context.lazyInitialize();
47
48     auto gainNode = adoptRef(*new GainNode(context));
49
50     auto result = gainNode->handleAudioNodeOptions(options, { 2, ChannelCountMode::Max, ChannelInterpretation::Speakers });
51     if (result.hasException())
52         return result.releaseException();
53
54     gainNode->gain().setValue(options.gain);
55
56     return gainNode;
57 }
58
59 GainNode::GainNode(BaseAudioContext& context)
60     : AudioNode(context)
61     , m_sampleAccurateGainValues(AudioUtilities::renderQuantumSize) // FIXME: can probably share temp buffer in context
62     , m_gain(AudioParam::create(context, "gain"_s, 1.0, -FLT_MAX, FLT_MAX, AutomationRate::ARate))
63 {
64     setNodeType(NodeTypeGain);
65
66     addInput();
67     addOutput(1);
68
69     initialize();
70 }
71
72 void GainNode::process(size_t framesToProcess)
73 {
74     // FIXME: for some cases there is a nice optimization to avoid processing here, and let the gain change
75     // happen in the summing junction input of the AudioNode we're connected to.
76     // Then we can avoid all of the following:
77
78     AudioBus* outputBus = output(0)->bus();
79     ASSERT(outputBus);
80
81     if (!isInitialized() || !input(0)->isConnected())
82         outputBus->zero();
83     else {
84         AudioBus* inputBus = input(0)->bus();
85
86         if (gain().hasSampleAccurateValues() && gain().automationRate() == AutomationRate::ARate) {
87             // Apply sample-accurate gain scaling for precise envelopes, grain windows, etc.
88             ASSERT(framesToProcess <= m_sampleAccurateGainValues.size());
89             if (framesToProcess <= m_sampleAccurateGainValues.size()) {
90                 float* gainValues = m_sampleAccurateGainValues.data();
91                 gain().calculateSampleAccurateValues(gainValues, framesToProcess);
92                 outputBus->copyWithSampleAccurateGainValuesFrom(*inputBus, gainValues, framesToProcess);
93             }
94         } else {
95             // Apply the gain with de-zippering into the output bus.
96             float gain = this->gain().hasSampleAccurateValues() ? this->gain().finalValue() : this->gain().value();
97             if (!gain) {
98                 // If the gain is 0 just zero the bus.
99                 outputBus->zero();
100             } else
101                 outputBus->copyWithGainFrom(*inputBus, gain);
102         }
103     }
104 }
105
106 void GainNode::processOnlyAudioParams(size_t framesToProcess)
107 {
108     float values[AudioUtilities::renderQuantumSize];
109     ASSERT(framesToProcess <= AudioUtilities::renderQuantumSize);
110
111     m_gain->calculateSampleAccurateValues(values, framesToProcess);
112 }
113
114 // FIXME: this can go away when we do mixing with gain directly in summing junction of AudioNodeInput
115 //
116 // As soon as we know the channel count of our input, we can lazily initialize.
117 // Sometimes this may be called more than once with different channel counts, in which case we must safely
118 // uninitialize and then re-initialize with the new channel count.
119 void GainNode::checkNumberOfChannelsForInput(AudioNodeInput* input)
120 {
121     ASSERT(context().isAudioThread() && context().isGraphOwner());
122
123     ASSERT(input && input == this->input(0));
124     if (input != this->input(0))
125         return;
126         
127     unsigned numberOfChannels = input->numberOfChannels();    
128
129     if (isInitialized() && numberOfChannels != output(0)->numberOfChannels()) {
130         // We're already initialized but the channel count has changed.
131         uninitialize();
132     }
133
134     if (!isInitialized()) {
135         // This will propagate the channel count to any nodes connected further downstream in the graph.
136         output(0)->setNumberOfChannels(numberOfChannels);
137         initialize();
138     }
139
140     AudioNode::checkNumberOfChannelsForInput(input);
141 }
142
143 } // namespace WebCore
144
145 #endif // ENABLE(WEB_AUDIO)