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