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