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(&currentDestinationBus, 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