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 "AudioBufferSourceNode.h" 3028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 3128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "AudioContext.h" 3228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "AudioNodeOutput.h" 3328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include <algorithm> 34f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include <wtf/MathExtras.h> 3528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 3628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuusing namespace std; 3728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 3828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhunamespace WebCore { 3928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 4028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuconst double DefaultGrainDuration = 0.020; // 20ms 4128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 4228040489d744e0c5d475a88663056c9040ed5320Teng-Hui ZhuPassRefPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, double sampleRate) 4328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 4428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return adoptRef(new AudioBufferSourceNode(context, sampleRate)); 4528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 4628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 4728040489d744e0c5d475a88663056c9040ed5320Teng-Hui ZhuAudioBufferSourceNode::AudioBufferSourceNode(AudioContext* context, double sampleRate) 4828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu : AudioSourceNode(context, sampleRate) 4928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_buffer(0) 5028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_isPlaying(false) 5128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_isLooping(false) 5228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_hasFinished(false) 5328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_startTime(0.0) 5428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_schedulingFrameDelay(0) 5528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_readIndex(0) 5628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_isGrain(false) 5728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_grainOffset(0.0) 5828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_grainDuration(DefaultGrainDuration) 5928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_grainFrameCount(0) 6028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_lastGain(1.0) 6128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu , m_pannerNode(0) 6228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 6328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu setType(NodeTypeAudioBufferSource); 6428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 6528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_gain = AudioGain::create("gain", 1.0, 0.0, 1.0); 6628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_playbackRate = AudioParam::create("playbackRate", 1.0, 0.0, AudioResampler::MaxRate); 6728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 6828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Default to mono. A call to setBuffer() will set the number of output channels to that of the buffer. 6928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu addOutput(adoptPtr(new AudioNodeOutput(this, 1))); 7028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 7128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu initialize(); 7228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 7328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 7428040489d744e0c5d475a88663056c9040ed5320Teng-Hui ZhuAudioBufferSourceNode::~AudioBufferSourceNode() 7528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 7628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu uninitialize(); 7728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 7828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 7928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid AudioBufferSourceNode::process(size_t framesToProcess) 8028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 8128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu AudioBus* outputBus = output(0)->bus(); 8228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 8328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!isInitialized()) { 8428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu outputBus->zero(); 8528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 8628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 8728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 8828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // The audio thread can't block on this lock, so we call tryLock() instead. 8928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Careful - this is a tryLock() and not an autolocker, so we must unlock() before every return. 9028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_processLock.tryLock()) { 9128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Check if it's time to start playing. 9228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double sampleRate = this->sampleRate(); 9328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double pitchRate = totalPitchRate(); 9428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double quantumStartTime = context()->currentTime(); 9528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double quantumEndTime = quantumStartTime + framesToProcess / sampleRate; 9628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 9728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!m_isPlaying || m_hasFinished || !buffer() || m_startTime >= quantumEndTime) { 9828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // FIXME: can optimize here by propagating silent hint instead of forcing the whole chain to process silence. 9928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu outputBus->zero(); 10028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_processLock.unlock(); 10128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 10228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 10328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 10428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Handle sample-accurate scheduling so that buffer playback will happen at a very precise time. 10528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_schedulingFrameDelay = 0; 10628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_startTime >= quantumStartTime) { 10728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // m_schedulingFrameDelay is set here only the very first render quantum (because of above check: m_startTime >= quantumEndTime) 10828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // So: quantumStartTime <= m_startTime < quantumEndTime 10928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(m_startTime < quantumEndTime); 11028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 11128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double startTimeInQuantum = m_startTime - quantumStartTime; 11228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double startFrameInQuantum = startTimeInQuantum * sampleRate; 11328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 11428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // m_schedulingFrameDelay is used in provideInput(), so factor in the current playback pitch rate. 11528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_schedulingFrameDelay = static_cast<int>(pitchRate * startFrameInQuantum); 11628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 11728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 11828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // FIXME: optimization opportunity: 11928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // With a bit of work, it should be possible to avoid going through the resampler completely when the pitchRate == 1, 12028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // especially if the pitchRate has never deviated from 1 in the past. 12128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 12228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Read the samples through the pitch resampler. Our provideInput() method will be called by the resampler. 12328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_resampler.setRate(pitchRate); 12428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_resampler.process(this, outputBus, framesToProcess); 12528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 12628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Apply the gain (in-place) to the output bus. 12728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double totalGain = gain()->value() * m_buffer->gain(); 12828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu outputBus->copyWithGainFrom(*outputBus, &m_lastGain, totalGain); 12928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 13028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_processLock.unlock(); 13128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } else { 13228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Too bad - the tryLock() failed. We must be in the middle of changing buffers and were already outputting silence anyway. 13328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu outputBus->zero(); 13428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 13528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 13628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 13728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu// The resampler calls us back here to get the input samples from our buffer. 13828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid AudioBufferSourceNode::provideInput(AudioBus* bus, size_t numberOfFrames) 13928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 14028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(context()->isAudioThread()); 14128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 14228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Basic sanity checking 14328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(bus); 14428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(buffer()); 14528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!bus || !buffer()) 14628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 14728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 14828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu unsigned numberOfChannels = this->numberOfChannels(); 14928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu unsigned busNumberOfChannels = bus->numberOfChannels(); 15028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 15128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // FIXME: we can add support for sources with more than two channels, but this is not a common case. 15228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu bool channelCountGood = numberOfChannels == busNumberOfChannels && (numberOfChannels == 1 || numberOfChannels == 2); 15328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(channelCountGood); 15428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!channelCountGood) 15528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 15628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 15728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Get the destination pointers. 15828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu float* destinationL = bus->channel(0)->data(); 15928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(destinationL); 16028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!destinationL) 16128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 16228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu float* destinationR = (numberOfChannels < 2) ? 0 : bus->channel(1)->data(); 16328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 16428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu size_t bufferLength = buffer()->length(); 16528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double bufferSampleRate = buffer()->sampleRate(); 16628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 16728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Calculate the start and end frames in our buffer that we want to play. 16828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // If m_isGrain is true, then we will be playing a portion of the total buffer. 16928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu unsigned startFrame = m_isGrain ? static_cast<unsigned>(m_grainOffset * bufferSampleRate) : 0; 17028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu unsigned endFrame = m_isGrain ? static_cast<unsigned>(startFrame + m_grainDuration * bufferSampleRate) : bufferLength; 17128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 17228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // This is a HACK to allow for HRTF tail-time - avoids glitch at end. 17328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // FIXME: implement tailTime for each AudioNode for a more general solution to this problem. 17428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_isGrain) 17528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu endFrame += 512; 17628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 17728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Do some sanity checking. 17828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (startFrame >= bufferLength) 17928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu startFrame = !bufferLength ? 0 : bufferLength - 1; 18028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (endFrame > bufferLength) 18128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu endFrame = bufferLength; 18228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_readIndex >= endFrame) 18328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_readIndex = startFrame; // reset to start 18428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 18528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu int framesToProcess = numberOfFrames; 18628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 18728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Handle sample-accurate scheduling so that we play the buffer at a very precise time. 18828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // m_schedulingFrameDelay will only be non-zero the very first time that provideInput() is called, which corresponds 18928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // with the very start of the buffer playback. 19028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_schedulingFrameDelay > 0) { 19128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(m_schedulingFrameDelay <= framesToProcess); 19228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_schedulingFrameDelay <= framesToProcess) { 19328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Generate silence for the initial portion of the destination. 19428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu memset(destinationL, 0, sizeof(float) * m_schedulingFrameDelay); 19528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu destinationL += m_schedulingFrameDelay; 19628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (destinationR) { 19728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu memset(destinationR, 0, sizeof(float) * m_schedulingFrameDelay); 19828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu destinationR += m_schedulingFrameDelay; 19928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 20028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 20128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Since we just generated silence for the initial portion, we have fewer frames to provide. 20228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu framesToProcess -= m_schedulingFrameDelay; 20328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 20428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 20528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 20628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // We have to generate a certain number of output sample-frames, but we need to handle the case where we wrap around 20728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // from the end of the buffer to the start if playing back with looping and also the case where we simply reach the 20828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // end of the sample data, but haven't yet rendered numberOfFrames worth of output. 20928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu while (framesToProcess > 0) { 21028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(m_readIndex <= endFrame); 21128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_readIndex > endFrame) 21228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 21328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 21428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Figure out how many frames we can process this time. 21528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu int framesAvailable = endFrame - m_readIndex; 21628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu int framesThisTime = min(framesToProcess, framesAvailable); 21728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 21828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Create the destination bus for the part of the destination we're processing this time. 21928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu AudioBus currentDestinationBus(busNumberOfChannels, framesThisTime, false); 22028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu currentDestinationBus.setChannelMemory(0, destinationL, framesThisTime); 22128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (busNumberOfChannels > 1) 22228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu currentDestinationBus.setChannelMemory(1, destinationR, framesThisTime); 22328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 22428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Generate output from the buffer. 22528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu readFromBuffer(¤tDestinationBus, framesThisTime); 22628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 22728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Update the destination pointers. 22828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu destinationL += framesThisTime; 22928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (busNumberOfChannels > 1) 23028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu destinationR += framesThisTime; 23128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 23228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu framesToProcess -= framesThisTime; 23328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 23428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Handle the case where we reach the end of the part of the sample data we're supposed to play for the buffer. 23528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_readIndex >= endFrame) { 23628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_readIndex = startFrame; 23728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_grainFrameCount = 0; 23828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 23928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!looping()) { 24028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // If we're not looping, then stop playing when we get to the end. 24128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_isPlaying = false; 24228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 24328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (framesToProcess > 0) { 24428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // We're not looping and we've reached the end of the sample data, but we still need to provide more output, 24528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // so generate silence for the remaining. 24628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu memset(destinationL, 0, sizeof(float) * framesToProcess); 24728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 24828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (destinationR) 24928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu memset(destinationR, 0, sizeof(float) * framesToProcess); 25028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 25128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 25228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!m_hasFinished) { 25328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Let the context dereference this AudioNode. 25428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu context()->notifyNodeFinishedProcessing(this); 25528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_hasFinished = true; 25628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 25728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 25828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 25928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 26028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 26128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 26228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 26328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid AudioBufferSourceNode::readFromBuffer(AudioBus* destinationBus, size_t framesToProcess) 26428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 26528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu bool isBusGood = destinationBus && destinationBus->length() == framesToProcess && destinationBus->numberOfChannels() == numberOfChannels(); 26628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(isBusGood); 26728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!isBusGood) 26828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 26928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 27028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu unsigned numberOfChannels = this->numberOfChannels(); 27128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // FIXME: we can add support for sources with more than two channels, but this is not a common case. 27228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu bool channelCountGood = numberOfChannels == 1 || numberOfChannels == 2; 27328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(channelCountGood); 27428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!channelCountGood) 27528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 27628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 27728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Get pointers to the start of the sample buffer. 27828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu float* sourceL = m_buffer->getChannelData(0)->data(); 27928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu float* sourceR = m_buffer->numberOfChannels() == 2 ? m_buffer->getChannelData(1)->data() : 0; 28028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 28128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Sanity check buffer access. 28228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu bool isSourceGood = sourceL && (numberOfChannels == 1 || sourceR) && m_readIndex + framesToProcess <= m_buffer->length(); 28328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(isSourceGood); 28428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!isSourceGood) 28528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 28628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 28728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Offset the pointers to the current read position in the sample buffer. 28828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu sourceL += m_readIndex; 28928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu sourceR += m_readIndex; 29028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 29128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Get pointers to the destination. 29228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu float* destinationL = destinationBus->channel(0)->data(); 29328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu float* destinationR = numberOfChannels == 2 ? destinationBus->channel(1)->data() : 0; 29428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu bool isDestinationGood = destinationL && (numberOfChannels == 1 || destinationR); 29528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(isDestinationGood); 29628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!isDestinationGood) 29728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 29828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 29928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_isGrain) 30028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu readFromBufferWithGrainEnvelope(sourceL, sourceR, destinationL, destinationR, framesToProcess); 30128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu else { 30228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Simply copy the data from the source buffer to the destination. 30328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu memcpy(destinationL, sourceL, sizeof(float) * framesToProcess); 30428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (numberOfChannels == 2) 30528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu memcpy(destinationR, sourceR, sizeof(float) * framesToProcess); 30628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 30728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 30828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Advance the buffer's read index. 30928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_readIndex += framesToProcess; 31028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 31128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 31228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid AudioBufferSourceNode::readFromBufferWithGrainEnvelope(float* sourceL, float* sourceR, float* destinationL, float* destinationR, size_t framesToProcess) 31328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 31428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(sourceL && destinationL); 31528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!sourceL || !destinationL) 31628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 31728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 31828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu int grainFrameLength = static_cast<int>(m_grainDuration * m_buffer->sampleRate()); 31928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu bool isStereo = sourceR && destinationR; 32028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 32128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu int n = framesToProcess; 32228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu while (n--) { 32328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Apply the grain envelope. 32428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu float x = static_cast<float>(m_grainFrameCount) / static_cast<float>(grainFrameLength); 32528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_grainFrameCount++; 32628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 32728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu x = min(1.0f, x); 328f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch float grainEnvelope = sinf(piFloat * x); 32928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 33028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *destinationL++ = grainEnvelope * *sourceL++; 33128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 33228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (isStereo) 33328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *destinationR++ = grainEnvelope * *sourceR++; 33428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 33528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 33628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 33728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid AudioBufferSourceNode::reset() 33828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 33928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_resampler.reset(); 34028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_readIndex = 0; 34128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_grainFrameCount = 0; 34228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_lastGain = gain()->value(); 34328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 34428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 34528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid AudioBufferSourceNode::setBuffer(AudioBuffer* buffer) 34628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 34728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(isMainThread()); 34828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 34928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // The context must be locked since changing the buffer can re-configure the number of channels that are output. 35028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu AudioContext::AutoLocker contextLocker(context()); 35128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 35228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // This synchronizes with process(). 35328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu MutexLocker processLocker(m_processLock); 35428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 35528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (buffer) { 35628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Do any necesssary re-configuration to the buffer's number of channels. 35728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu unsigned numberOfChannels = buffer->numberOfChannels(); 35828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_resampler.configureChannels(numberOfChannels); 35928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu output(0)->setNumberOfChannels(numberOfChannels); 36028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 36128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 36228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_readIndex = 0; 36328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_buffer = buffer; 36428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 36528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 36628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuunsigned AudioBufferSourceNode::numberOfChannels() 36728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 36828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return output(0)->numberOfChannels(); 36928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 37028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 37128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid AudioBufferSourceNode::noteOn(double when) 37228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 37328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(isMainThread()); 37428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_isPlaying) 37528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 37628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 37728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_isGrain = false; 37828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_startTime = when; 37928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_readIndex = 0; 38028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_isPlaying = true; 38128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 38228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 38328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid AudioBufferSourceNode::noteGrainOn(double when, double grainOffset, double grainDuration) 38428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 38528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(isMainThread()); 38628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_isPlaying) 38728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 38828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 38928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!buffer()) 39028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 39128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 39228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Do sanity checking of grain parameters versus buffer size. 39328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double bufferDuration = buffer()->duration(); 39428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 39528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (grainDuration > bufferDuration) 39628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; // FIXME: maybe should throw exception - consider in specification. 39728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 39828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double maxGrainOffset = bufferDuration - grainDuration; 39928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu maxGrainOffset = max(0.0, maxGrainOffset); 40028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 40128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu grainOffset = max(0.0, grainOffset); 40228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu grainOffset = min(maxGrainOffset, grainOffset); 40328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_grainOffset = grainOffset; 40428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 40528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_grainDuration = grainDuration; 40628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_grainFrameCount = 0; 40728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 40828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_isGrain = true; 40928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_startTime = when; 41028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_readIndex = static_cast<int>(m_grainOffset * buffer()->sampleRate()); 41128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_isPlaying = true; 41228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 41328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 41428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid AudioBufferSourceNode::noteOff(double) 41528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 41628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(isMainThread()); 41728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!m_isPlaying) 41828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 41928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 42028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // FIXME: the "when" argument to this method is ignored. 42128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_isPlaying = false; 42228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_readIndex = 0; 42328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 42428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 42528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhudouble AudioBufferSourceNode::totalPitchRate() 42628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 42728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double dopplerRate = 1.0; 42828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (m_pannerNode.get()) 42928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu dopplerRate = m_pannerNode->dopplerRate(); 43028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 43128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Incorporate buffer's sample-rate versus AudioContext's sample-rate. 43228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case. 43328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double sampleRateFactor = 1.0; 43428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (buffer()) 43528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu sampleRateFactor = buffer()->sampleRate() / sampleRate(); 43628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 43728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double basePitchRate = playbackRate()->value(); 43828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 43928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu double totalRate = dopplerRate * sampleRateFactor * basePitchRate; 44028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 44128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Sanity check the total rate. It's very important that the resampler not get any bad rate values. 44228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu totalRate = max(0.0, totalRate); 44328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu totalRate = min(AudioResampler::MaxRate, totalRate); 44428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 44528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu bool isTotalRateValid = !isnan(totalRate) && !isinf(totalRate); 44628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(isTotalRateValid); 44728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!isTotalRateValid) 44828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu totalRate = 1.0; 44928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 45028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return totalRate; 45128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 45228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 45328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} // namespace WebCore 45428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 45528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#endif // ENABLE(WEB_AUDIO) 456