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