~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

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