1/*
2 * Copyright (C) 2010, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1.  Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2.  Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26
27#if ENABLE(WEB_AUDIO)
28
29#include "AudioBufferSourceNode.h"
30
31#include "AudioContext.h"
32#include "AudioNodeOutput.h"
33#include "AudioUtilities.h"
34#include "FloatConversion.h"
35#include "ScriptCallStack.h"
36#include "ScriptController.h"
37#include "ScriptExecutionContext.h"
38#include <algorithm>
39#include <wtf/MainThread.h>
40#include <wtf/MathExtras.h>
41
42using namespace std;
43
44namespace WebCore {
45
46const double DefaultGrainDuration = 0.020; // 20ms
47
48// Arbitrary upper limit on playback rate.
49// Higher than expected rates can be useful when playing back oversampled buffers
50// to minimize linear interpolation aliasing.
51const double MaxRate = 1024;
52
53PassRefPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, float sampleRate)
54{
55    return adoptRef(new AudioBufferSourceNode(context, sampleRate));
56}
57
58AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* context, float sampleRate)
59    : AudioScheduledSourceNode(context, sampleRate)
60    , m_buffer(0)
61    , m_isLooping(false)
62    , m_loopStart(0)
63    , m_loopEnd(0)
64    , m_virtualReadIndex(0)
65    , m_isGrain(false)
66    , m_grainOffset(0.0)
67    , m_grainDuration(DefaultGrainDuration)
68    , m_lastGain(1.0)
69    , m_pannerNode(0)
70{
71    setNodeType(NodeTypeAudioBufferSource);
72
73    m_gain = AudioParam::create(context, "gain", 1.0, 0.0, 1.0);
74    m_playbackRate = AudioParam::create(context, "playbackRate", 1.0, 0.0, MaxRate);
75
76    // Default to mono.  A call to setBuffer() will set the number of output channels to that of the buffer.
77    addOutput(adoptPtr(new AudioNodeOutput(this, 1)));
78
79    initialize();
80}
81
82AudioBufferSourceNode::~AudioBufferSourceNode()
83{
84    clearPannerNode();
85    uninitialize();
86}
87
88void AudioBufferSourceNode::process(size_t framesToProcess)
89{
90    AudioBus* outputBus = output(0)->bus();
91
92    if (!isInitialized()) {
93        outputBus->zero();
94        return;
95    }
96
97    // The audio thread can't block on this lock, so we call tryLock() instead.
98    MutexTryLocker tryLocker(m_processLock);
99    if (tryLocker.locked()) {
100        if (!buffer()) {
101            outputBus->zero();
102            return;
103        }
104
105        // After calling setBuffer() with a buffer having a different number of channels, there can in rare cases be a slight delay
106        // before the output bus is updated to the new number of channels because of use of tryLocks() in the context's updating system.
107        // In this case, if the the buffer has just been changed and we're not quite ready yet, then just output silence.
108        if (numberOfChannels() != buffer()->numberOfChannels()) {
109            outputBus->zero();
110            return;
111        }
112
113        size_t quantumFrameOffset;
114        size_t bufferFramesToProcess;
115
116        updateSchedulingInfo(framesToProcess,
117                             outputBus,
118                             quantumFrameOffset,
119                             bufferFramesToProcess);
120
121        if (!bufferFramesToProcess) {
122            outputBus->zero();
123            return;
124        }
125
126        for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i)
127            m_destinationChannels[i] = outputBus->channel(i)->mutableData();
128
129        // Render by reading directly from the buffer.
130        if (!renderFromBuffer(outputBus, quantumFrameOffset, bufferFramesToProcess)) {
131            outputBus->zero();
132            return;
133        }
134
135        // Apply the gain (in-place) to the output bus.
136        float totalGain = gain()->value() * m_buffer->gain();
137        outputBus->copyWithGainFrom(*outputBus, &m_lastGain, totalGain);
138        outputBus->clearSilentFlag();
139    } else {
140        // Too bad - the tryLock() failed.  We must be in the middle of changing buffers and were already outputting silence anyway.
141        outputBus->zero();
142    }
143}
144
145// Returns true if we're finished.
146bool AudioBufferSourceNode::renderSilenceAndFinishIfNotLooping(AudioBus*, unsigned index, size_t framesToProcess)
147{
148    if (!loop()) {
149        // If we're not looping, then stop playing when we get to the end.
150
151        if (framesToProcess > 0) {
152            // We're not looping and we've reached the end of the sample data, but we still need to provide more output,
153            // so generate silence for the remaining.
154            for (unsigned i = 0; i < numberOfChannels(); ++i)
155                memset(m_destinationChannels[i] + index, 0, sizeof(float) * framesToProcess);
156        }
157
158        finish();
159        return true;
160    }
161    return false;
162}
163
164bool AudioBufferSourceNode::renderFromBuffer(AudioBus* bus, unsigned destinationFrameOffset, size_t numberOfFrames)
165{
166    ASSERT(context()->isAudioThread());
167
168    // Basic sanity checking
169    ASSERT(bus);
170    ASSERT(buffer());
171    if (!bus || !buffer())
172        return false;
173
174    unsigned numberOfChannels = this->numberOfChannels();
175    unsigned busNumberOfChannels = bus->numberOfChannels();
176
177    bool channelCountGood = numberOfChannels && numberOfChannels == busNumberOfChannels;
178    ASSERT(channelCountGood);
179    if (!channelCountGood)
180        return false;
181
182    // Sanity check destinationFrameOffset, numberOfFrames.
183    size_t destinationLength = bus->length();
184
185    bool isLengthGood = destinationLength <= 4096 && numberOfFrames <= 4096;
186    ASSERT(isLengthGood);
187    if (!isLengthGood)
188        return false;
189
190    bool isOffsetGood = destinationFrameOffset <= destinationLength && destinationFrameOffset + numberOfFrames <= destinationLength;
191    ASSERT(isOffsetGood);
192    if (!isOffsetGood)
193        return false;
194
195    // Potentially zero out initial frames leading up to the offset.
196    if (destinationFrameOffset) {
197        for (unsigned i = 0; i < numberOfChannels; ++i)
198            memset(m_destinationChannels[i], 0, sizeof(float) * destinationFrameOffset);
199    }
200
201    // Offset the pointers to the correct offset frame.
202    unsigned writeIndex = destinationFrameOffset;
203
204    size_t bufferLength = buffer()->length();
205    double bufferSampleRate = buffer()->sampleRate();
206
207    // Avoid converting from time to sample-frames twice by computing
208    // the grain end time first before computing the sample frame.
209    unsigned endFrame = m_isGrain ? AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, bufferSampleRate) : bufferLength;
210
211    // This is a HACK to allow for HRTF tail-time - avoids glitch at end.
212    // FIXME: implement tailTime for each AudioNode for a more general solution to this problem.
213    // https://bugs.webkit.org/show_bug.cgi?id=77224
214    if (m_isGrain)
215        endFrame += 512;
216
217    // Do some sanity checking.
218    if (endFrame > bufferLength)
219        endFrame = bufferLength;
220    if (m_virtualReadIndex >= endFrame)
221        m_virtualReadIndex = 0; // reset to start
222
223    // If the .loop attribute is true, then values of m_loopStart == 0 && m_loopEnd == 0 implies
224    // that we should use the entire buffer as the loop, otherwise use the loop values in m_loopStart and m_loopEnd.
225    double virtualEndFrame = endFrame;
226    double virtualDeltaFrames = endFrame;
227
228    if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 && m_loopEnd > 0 && m_loopStart < m_loopEnd) {
229        // Convert from seconds to sample-frames.
230        double loopStartFrame = m_loopStart * buffer()->sampleRate();
231        double loopEndFrame = m_loopEnd * buffer()->sampleRate();
232
233        virtualEndFrame = min(loopEndFrame, virtualEndFrame);
234        virtualDeltaFrames = virtualEndFrame - loopStartFrame;
235    }
236
237
238    double pitchRate = totalPitchRate();
239
240    // Sanity check that our playback rate isn't larger than the loop size.
241    if (pitchRate >= virtualDeltaFrames)
242        return false;
243
244    // Get local copy.
245    double virtualReadIndex = m_virtualReadIndex;
246
247    // Render loop - reading from the source buffer to the destination using linear interpolation.
248    int framesToProcess = numberOfFrames;
249
250    const float** sourceChannels = m_sourceChannels.get();
251    float** destinationChannels = m_destinationChannels.get();
252
253    // Optimize for the very common case of playing back with pitchRate == 1.
254    // We can avoid the linear interpolation.
255    if (pitchRate == 1 && virtualReadIndex == floor(virtualReadIndex)
256        && virtualDeltaFrames == floor(virtualDeltaFrames)
257        && virtualEndFrame == floor(virtualEndFrame)) {
258        unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
259        unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames);
260        endFrame = static_cast<unsigned>(virtualEndFrame);
261        while (framesToProcess > 0) {
262            int framesToEnd = endFrame - readIndex;
263            int framesThisTime = min(framesToProcess, framesToEnd);
264            framesThisTime = max(0, framesThisTime);
265
266            for (unsigned i = 0; i < numberOfChannels; ++i)
267                memcpy(destinationChannels[i] + writeIndex, sourceChannels[i] + readIndex, sizeof(float) * framesThisTime);
268
269            writeIndex += framesThisTime;
270            readIndex += framesThisTime;
271            framesToProcess -= framesThisTime;
272
273            // Wrap-around.
274            if (readIndex >= endFrame) {
275                readIndex -= deltaFrames;
276                if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
277                    break;
278            }
279        }
280        virtualReadIndex = readIndex;
281    } else {
282        while (framesToProcess--) {
283            unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
284            double interpolationFactor = virtualReadIndex - readIndex;
285
286            // For linear interpolation we need the next sample-frame too.
287            unsigned readIndex2 = readIndex + 1;
288            if (readIndex2 >= bufferLength) {
289                if (loop()) {
290                    // Make sure to wrap around at the end of the buffer.
291                    readIndex2 = static_cast<unsigned>(virtualReadIndex + 1 - virtualDeltaFrames);
292                } else
293                    readIndex2 = readIndex;
294            }
295
296            // Final sanity check on buffer access.
297            // FIXME: as an optimization, try to get rid of this inner-loop check and put assertions and guards before the loop.
298            if (readIndex >= bufferLength || readIndex2 >= bufferLength)
299                break;
300
301            // Linear interpolation.
302            for (unsigned i = 0; i < numberOfChannels; ++i) {
303                float* destination = destinationChannels[i];
304                const float* source = sourceChannels[i];
305
306                double sample1 = source[readIndex];
307                double sample2 = source[readIndex2];
308                double sample = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2;
309
310                destination[writeIndex] = narrowPrecisionToFloat(sample);
311            }
312            writeIndex++;
313
314            virtualReadIndex += pitchRate;
315
316            // Wrap-around, retaining sub-sample position since virtualReadIndex is floating-point.
317            if (virtualReadIndex >= virtualEndFrame) {
318                virtualReadIndex -= virtualDeltaFrames;
319                if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
320                    break;
321            }
322        }
323    }
324
325    bus->clearSilentFlag();
326
327    m_virtualReadIndex = virtualReadIndex;
328
329    return true;
330}
331
332
333void AudioBufferSourceNode::reset()
334{
335    m_virtualReadIndex = 0;
336    m_lastGain = gain()->value();
337}
338
339bool AudioBufferSourceNode::setBuffer(AudioBuffer* buffer)
340{
341    ASSERT(isMainThread());
342
343    // The context must be locked since changing the buffer can re-configure the number of channels that are output.
344    AudioContext::AutoLocker contextLocker(context());
345
346    // This synchronizes with process().
347    MutexLocker processLocker(m_processLock);
348
349    if (buffer) {
350        // Do any necesssary re-configuration to the buffer's number of channels.
351        unsigned numberOfChannels = buffer->numberOfChannels();
352
353        if (numberOfChannels > AudioContext::maxNumberOfChannels())
354            return false;
355
356        output(0)->setNumberOfChannels(numberOfChannels);
357
358        m_sourceChannels = adoptArrayPtr(new const float* [numberOfChannels]);
359        m_destinationChannels = adoptArrayPtr(new float* [numberOfChannels]);
360
361        for (unsigned i = 0; i < numberOfChannels; ++i)
362            m_sourceChannels[i] = buffer->getChannelData(i)->data();
363    }
364
365    m_virtualReadIndex = 0;
366    m_buffer = buffer;
367
368    return true;
369}
370
371unsigned AudioBufferSourceNode::numberOfChannels()
372{
373    return output(0)->numberOfChannels();
374}
375
376void AudioBufferSourceNode::startGrain(double when, double grainOffset)
377{
378    // Duration of 0 has special value, meaning calculate based on the entire buffer's duration.
379    startGrain(when, grainOffset, 0);
380}
381
382void AudioBufferSourceNode::startGrain(double when, double grainOffset, double grainDuration)
383{
384    ASSERT(isMainThread());
385
386    if (ScriptController::processingUserGesture())
387        context()->removeBehaviorRestriction(AudioContext::RequireUserGestureForAudioStartRestriction);
388
389    if (m_playbackState != UNSCHEDULED_STATE)
390        return;
391
392    if (!buffer())
393        return;
394
395    // Do sanity checking of grain parameters versus buffer size.
396    double bufferDuration = buffer()->duration();
397
398    grainOffset = max(0.0, grainOffset);
399    grainOffset = min(bufferDuration, grainOffset);
400    m_grainOffset = grainOffset;
401
402    // Handle default/unspecified duration.
403    double maxDuration = bufferDuration - grainOffset;
404    if (!grainDuration)
405        grainDuration = maxDuration;
406
407    grainDuration = max(0.0, grainDuration);
408    grainDuration = min(maxDuration, grainDuration);
409    m_grainDuration = grainDuration;
410
411    m_isGrain = true;
412    m_startTime = when;
413
414    // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation
415    // at a sub-sample position since it will degrade the quality.
416    // When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer.
417    // Since playbackRate == 1 is very common, it's worth considering quality.
418    m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer()->sampleRate());
419
420    m_playbackState = SCHEDULED_STATE;
421}
422
423#if ENABLE(LEGACY_WEB_AUDIO)
424void AudioBufferSourceNode::noteGrainOn(double when, double grainOffset, double grainDuration)
425{
426    startGrain(when, grainOffset, grainDuration);
427}
428#endif
429
430double AudioBufferSourceNode::totalPitchRate()
431{
432    double dopplerRate = 1.0;
433    if (m_pannerNode)
434        dopplerRate = m_pannerNode->dopplerRate();
435
436    // Incorporate buffer's sample-rate versus AudioContext's sample-rate.
437    // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case.
438    double sampleRateFactor = 1.0;
439    if (buffer())
440        sampleRateFactor = buffer()->sampleRate() / sampleRate();
441
442    double basePitchRate = playbackRate()->value();
443
444    double totalRate = dopplerRate * sampleRateFactor * basePitchRate;
445
446    // Sanity check the total rate.  It's very important that the resampler not get any bad rate values.
447    totalRate = max(0.0, totalRate);
448    if (!totalRate)
449        totalRate = 1; // zero rate is considered illegal
450    totalRate = min(MaxRate, totalRate);
451
452    bool isTotalRateValid = !std::isnan(totalRate) && !std::isinf(totalRate);
453    ASSERT(isTotalRateValid);
454    if (!isTotalRateValid)
455        totalRate = 1.0;
456
457    return totalRate;
458}
459
460bool AudioBufferSourceNode::looping()
461{
462    static bool firstTime = true;
463    if (firstTime && context() && context()->scriptExecutionContext()) {
464        context()->scriptExecutionContext()->addConsoleMessage(JSMessageSource, WarningMessageLevel, "AudioBufferSourceNode 'looping' attribute is deprecated.  Use 'loop' instead.");
465        firstTime = false;
466    }
467
468    return m_isLooping;
469}
470
471void AudioBufferSourceNode::setLooping(bool looping)
472{
473    static bool firstTime = true;
474    if (firstTime && context() && context()->scriptExecutionContext()) {
475        context()->scriptExecutionContext()->addConsoleMessage(JSMessageSource, WarningMessageLevel, "AudioBufferSourceNode 'looping' attribute is deprecated.  Use 'loop' instead.");
476        firstTime = false;
477    }
478
479    m_isLooping = looping;
480}
481
482bool AudioBufferSourceNode::propagatesSilence() const
483{
484    return !isPlayingOrScheduled() || hasFinished() || !m_buffer;
485}
486
487void AudioBufferSourceNode::setPannerNode(PannerNode* pannerNode)
488{
489    if (m_pannerNode != pannerNode && !hasFinished()) {
490        if (pannerNode)
491            pannerNode->ref(AudioNode::RefTypeConnection);
492        if (m_pannerNode)
493            m_pannerNode->deref(AudioNode::RefTypeConnection);
494
495        m_pannerNode = pannerNode;
496    }
497}
498
499void AudioBufferSourceNode::clearPannerNode()
500{
501    if (m_pannerNode) {
502        m_pannerNode->deref(AudioNode::RefTypeConnection);
503        m_pannerNode = 0;
504    }
505}
506
507void AudioBufferSourceNode::finish()
508{
509    clearPannerNode();
510    ASSERT(!m_pannerNode);
511    AudioScheduledSourceNode::finish();
512}
513
514} // namespace WebCore
515
516#endif // ENABLE(WEB_AUDIO)
517