128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu/*
228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * Copyright (C) 2010, Google Inc. All rights reserved.
328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *
428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * Redistribution and use in source and binary forms, with or without
528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * modification, are permitted provided that the following conditions
628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * are met:
728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * 1.  Redistributions of source code must retain the above copyright
828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *    notice, this list of conditions and the following disclaimer.
928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * 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.
1228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *
1328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
1428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * 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
1728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * (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.
2328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu */
2428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
2528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "config.h"
2628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
2728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#if ENABLE(WEB_AUDIO)
2828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
2928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "ConvolverNode.h"
3028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
3128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "AudioBuffer.h"
322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "AudioContext.h"
3328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "AudioNodeInput.h"
3428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "AudioNodeOutput.h"
3528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "Reverb.h"
3628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
3728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu// Note about empirical tuning:
3828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu// The maximum FFT size affects reverb performance and accuracy.
3928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu// If the reverb is single-threaded and processes entirely in the real-time audio thread,
4028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu// it's important not to make this too high.  In this case 8192 is a good value.
4128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu// But, the Reverb object is multi-threaded, so we want this as high as possible without losing too much accuracy.
4228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu// Very large FFTs will have worse phase errors.  Given these constraints 16384 is a good compromise.
4328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuconst size_t MaxFFTSize = 16384;
4428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
4528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhunamespace WebCore {
4628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
4728040489d744e0c5d475a88663056c9040ed5320Teng-Hui ZhuConvolverNode::ConvolverNode(AudioContext* context, double sampleRate)
4828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    : AudioNode(context, sampleRate)
4928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
5028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    addInput(adoptPtr(new AudioNodeInput(this)));
5128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    addOutput(adoptPtr(new AudioNodeOutput(this, 2)));
5228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
5328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    setType(NodeTypeConvolver);
5428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
5528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    initialize();
5628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
5728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
5828040489d744e0c5d475a88663056c9040ed5320Teng-Hui ZhuConvolverNode::~ConvolverNode()
5928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
6028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    uninitialize();
6128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
6228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
6328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid ConvolverNode::process(size_t framesToProcess)
6428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
6528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    AudioBus* outputBus = output(0)->bus();
6628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(outputBus);
6728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
6828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Synchronize with possible dynamic changes to the impulse response.
6928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (m_processLock.tryLock()) {
7028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        if (!isInitialized() || !m_reverb.get())
7128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            outputBus->zero();
7228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        else {
7328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            // Process using the convolution engine.
7428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            // Note that we can handle the case where nothing is connected to the input, in which case we'll just feed silence into the convolver.
7528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            // FIXME:  If we wanted to get fancy we could try to factor in the 'tail time' and stop processing once the tail dies down if
7628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            // we keep getting fed silence.
7728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            m_reverb->process(input(0)->bus(), outputBus, framesToProcess);
7828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        }
7928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
8028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_processLock.unlock();
8128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    } else {
8228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        // Too bad - the tryLock() failed.  We must be in the middle of setting a new impulse response.
8328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        outputBus->zero();
8428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
8528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
8628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
8728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid ConvolverNode::reset()
8828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
8928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    MutexLocker locker(m_processLock);
9028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (m_reverb.get())
9128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_reverb->reset();
9228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
9328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
9428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid ConvolverNode::initialize()
9528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
9628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (isInitialized())
9728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return;
9828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
9928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    AudioNode::initialize();
10028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
10128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
10228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid ConvolverNode::uninitialize()
10328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
10428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (!isInitialized())
10528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return;
10628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
10728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    m_reverb.clear();
10828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    AudioNode::uninitialize();
10928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
11028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
11128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid ConvolverNode::setBuffer(AudioBuffer* buffer)
11228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
11328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isMainThread());
11428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
11528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(buffer);
11628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (!buffer)
11728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return;
11828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
11928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    unsigned numberOfChannels = buffer->numberOfChannels();
12028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    size_t bufferLength = buffer->length();
12128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
12228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // The current implementation supports up to four channel impulse responses, which are interpreted as true-stereo (see Reverb class).
12328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    bool isBufferGood = numberOfChannels > 0 && numberOfChannels <= 4 && bufferLength;
12428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isBufferGood);
12528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (!isBufferGood)
12628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return;
12728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
12828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Wrap the AudioBuffer by an AudioBus. It's an efficient pointer set and not a memcpy().
12928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // This memory is simply used in the Reverb constructor and no reference to it is kept for later use in that class.
13028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    AudioBus bufferBus(numberOfChannels, bufferLength, false);
13128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    for (unsigned i = 0; i < numberOfChannels; ++i)
13228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        bufferBus.setChannelMemory(i, buffer->getChannelData(i)->data(), bufferLength);
13328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
13428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Create the reverb with the given impulse response.
1352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    bool useBackgroundThreads = !context()->isOfflineContext();
1362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    OwnPtr<Reverb> reverb = adoptPtr(new Reverb(&bufferBus, AudioNode::ProcessingSizeInFrames, MaxFFTSize, 2, useBackgroundThreads));
13728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
13828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    {
13928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        // Synchronize with process().
14028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        MutexLocker locker(m_processLock);
14128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_reverb = reverb.release();
14228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_buffer = buffer;
14328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
14428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
14528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
14628040489d744e0c5d475a88663056c9040ed5320Teng-Hui ZhuAudioBuffer* ConvolverNode::buffer()
14728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
14828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isMainThread());
14928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    return m_buffer.get();
15028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
15128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
15228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} // namespace WebCore
15328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
15428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#endif // ENABLE(WEB_AUDIO)
155