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