1a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch/*
228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * Copyright (C) 2010, Google Inc. All rights reserved.
3a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *
4a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Redistribution and use in source and binary forms, with or without
5a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * modification, are permitted provided that the following conditions
6a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * are met:
7a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 1.  Redistributions of source code must retain the above copyright
828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *    notice, this list of conditions and the following disclaimer.
9a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 2.  Redistributions in binary form must reproduce the above copyright
1028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *    notice, this list of conditions and the following disclaimer in the
1128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *    documentation and/or other materials provided with the distribution.
12a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *
1328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch */
24a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
25a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "config.h"
26a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
27a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#if ENABLE(WEB_AUDIO)
28a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
29a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AudioGainNode.h"
30a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
31a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AudioBus.h"
32a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AudioNodeInput.h"
33a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AudioNodeOutput.h"
34a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
35a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochnamespace WebCore {
36a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
37a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochAudioGainNode::AudioGainNode(AudioContext* context, double sampleRate)
38a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    : AudioNode(context, sampleRate)
39a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_lastGain(1.0)
40a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
41a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_gain = AudioGain::create("gain", 1.0, 0.0, 1.0);
42a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
43a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    addInput(adoptPtr(new AudioNodeInput(this)));
44a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    addOutput(adoptPtr(new AudioNodeOutput(this, 1)));
45a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
46a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    setType(NodeTypeGain);
47a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
48a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    initialize();
49a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
50a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
51a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioGainNode::process(size_t /*framesToProcess*/)
52a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
53a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // FIXME: there is a nice optimization to avoid processing here, and let the gain change
54a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // happen in the summing junction input of the AudioNode we're connected to.
55a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Then we can avoid all of the following:
56a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
57a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    AudioBus* outputBus = output(0)->bus();
58a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(outputBus);
59a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
60a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // The realtime thread can't block on this lock, so we call tryLock() instead.
61a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (m_processLock.tryLock()) {
62a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!isInitialized() || !input(0)->isConnected())
63a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            outputBus->zero();
64a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        else {
65a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            AudioBus* inputBus = input(0)->bus();
66a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
67a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            // Apply the gain with de-zippering into the output bus.
68a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            outputBus->copyWithGainFrom(*inputBus, &m_lastGain, gain()->value());
69a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
70a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
71a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_processLock.unlock();
72a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    } else {
73a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Too bad - the tryLock() failed.  We must be in the middle of re-connecting and were already outputting silence anyway...
74a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        outputBus->zero();
75a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
76a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
77a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
78a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioGainNode::reset()
79a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
80a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Snap directly to desired gain.
81a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_lastGain = gain()->value();
82a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
83a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
84a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// FIXME: this can go away when we do mixing with gain directly in summing junction of AudioNodeInput
85a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch//
86a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// As soon as we know the channel count of our input, we can lazily initialize.
87a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// Sometimes this may be called more than once with different channel counts, in which case we must safely
88a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// uninitialize and then re-initialize with the new channel count.
89a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioGainNode::checkNumberOfChannelsForInput(AudioNodeInput* input)
90a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
91a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(input && input == this->input(0));
92a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (input != this->input(0))
93a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
94a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
95a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    unsigned numberOfChannels = input->numberOfChannels();
96a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
97a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (isInitialized() && numberOfChannels != output(0)->numberOfChannels()) {
98a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // We're already initialized but the channel count has changed.
99a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // We need to be careful since we may be actively processing right now, so synchronize with process().
100a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        MutexLocker locker(m_processLock);
101a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        uninitialize();
102a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
103a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
10428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (!isInitialized()) {
10528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        // This will propagate the channel count to any nodes connected further downstream in the graph.
10628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        output(0)->setNumberOfChannels(numberOfChannels);
10728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        initialize();
10828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
109a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
110a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
111a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} // namespace WebCore
112a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
113a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#endif // ENABLE(WEB_AUDIO)
114