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 "AudioBuffer.h"
32#include "AudioContext.h"
33#include "AudioNodeOutput.h"
34#include "AudioParam.h"
35#include "AudioUtilities.h"
36#include "FloatConversion.h"
37#include "PannerNode.h"
38#include "ScriptExecutionContext.h"
39#include <wtf/IsoMallocInlines.h>
40
41namespace WebCore {
42
43WTF_MAKE_ISO_ALLOCATED_IMPL(AudioBufferSourceNode);
44
45const 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.
50const double MaxRate = 1024;
51
52Ref<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext& context, float sampleRate)
53{
54 return adoptRef(*new AudioBufferSourceNode(context, sampleRate));
55}
56
57AudioBufferSourceNode::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_lastGain(1.0)
68 , m_pannerNode(nullptr)
69{
70 setNodeType(NodeTypeAudioBufferSource);
71
72 m_gain = AudioParam::create(context, "gain", 1.0, 0.0, 1.0);
73 m_playbackRate = AudioParam::create(context, "playbackRate", 1.0, -MaxRate, MaxRate);
74
75 // Default to mono. A call to setBuffer() will set the number of output channels to that of the buffer.
76 addOutput(std::make_unique<AudioNodeOutput>(this, 1));
77
78 initialize();
79}
80
81AudioBufferSourceNode::~AudioBufferSourceNode()
82{
83 clearPannerNode();
84 uninitialize();
85}
86
87void AudioBufferSourceNode::process(size_t framesToProcess)
88{
89 auto& 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 use std::try_to_lock instead.
97 std::unique_lock<Lock> lock(m_processMutex, std::try_to_lock);
98 if (!lock.owns_lock()) {
99 // Too bad - the try_lock() failed. We must be in the middle of changing buffers and were already outputting silence anyway.
100 outputBus.zero();
101 return;
102 }
103
104 if (!buffer()) {
105 outputBus.zero();
106 return;
107 }
108
109 // After calling setBuffer() with a buffer having a different number of channels, there can in rare cases be a slight delay
110 // before the output bus is updated to the new number of channels because of use of tryLocks() in the context's updating system.
111 // In this case, if the buffer has just been changed and we're not quite ready yet, then just output silence.
112 if (numberOfChannels() != buffer()->numberOfChannels()) {
113 outputBus.zero();
114 return;
115 }
116
117 size_t quantumFrameOffset = 0;
118 size_t bufferFramesToProcess = 0;
119 updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset, 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}
140
141// Returns true if we're finished.
142bool AudioBufferSourceNode::renderSilenceAndFinishIfNotLooping(AudioBus*, unsigned index, size_t framesToProcess)
143{
144 if (!loop()) {
145 // If we're not looping, then stop playing when we get to the end.
146
147 if (framesToProcess > 0) {
148 // We're not looping and we've reached the end of the sample data, but we still need to provide more output,
149 // so generate silence for the remaining.
150 for (unsigned i = 0; i < numberOfChannels(); ++i)
151 memset(m_destinationChannels[i] + index, 0, sizeof(float) * framesToProcess);
152 }
153
154 finish();
155 return true;
156 }
157 return false;
158}
159
160bool AudioBufferSourceNode::renderFromBuffer(AudioBus* bus, unsigned destinationFrameOffset, size_t numberOfFrames)
161{
162 ASSERT(context().isAudioThread());
163
164 // Basic sanity checking
165 ASSERT(bus);
166 ASSERT(buffer());
167 if (!bus || !buffer())
168 return false;
169
170 unsigned numberOfChannels = this->numberOfChannels();
171 unsigned busNumberOfChannels = bus->numberOfChannels();
172
173 bool channelCountGood = numberOfChannels && numberOfChannels == busNumberOfChannels;
174 ASSERT(channelCountGood);
175 if (!channelCountGood)
176 return false;
177
178 // Sanity check destinationFrameOffset, numberOfFrames.
179 size_t destinationLength = bus->length();
180
181 bool isLengthGood = destinationLength <= 4096 && numberOfFrames <= 4096;
182 ASSERT(isLengthGood);
183 if (!isLengthGood)
184 return false;
185
186 bool isOffsetGood = destinationFrameOffset <= destinationLength && destinationFrameOffset + numberOfFrames <= destinationLength;
187 ASSERT(isOffsetGood);
188 if (!isOffsetGood)
189 return false;
190
191 // Potentially zero out initial frames leading up to the offset.
192 if (destinationFrameOffset) {
193 for (unsigned i = 0; i < numberOfChannels; ++i)
194 memset(m_destinationChannels[i], 0, sizeof(float) * destinationFrameOffset);
195 }
196
197 // Offset the pointers to the correct offset frame.
198 unsigned writeIndex = destinationFrameOffset;
199
200 size_t bufferLength = buffer()->length();
201 double bufferSampleRate = buffer()->sampleRate();
202 double pitchRate = totalPitchRate();
203 bool reverse = pitchRate < 0;
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 maxFrame;
208 if (m_isGrain)
209 maxFrame = AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, bufferSampleRate);
210 else
211 maxFrame = bufferLength;
212
213 // Do some sanity checking.
214 if (maxFrame > bufferLength)
215 maxFrame = bufferLength;
216 if (reverse && m_virtualReadIndex <= 0)
217 m_virtualReadIndex = maxFrame - 1;
218 else if (!reverse && m_virtualReadIndex >= maxFrame)
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 virtualMaxFrame = maxFrame;
224 double virtualMinFrame = 0;
225 double virtualDeltaFrames = maxFrame;
226
227 if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 && m_loopEnd > 0 && m_loopStart < m_loopEnd) {
228 // Convert from seconds to sample-frames.
229 double loopMinFrame = m_loopStart * buffer()->sampleRate();
230 double loopMaxFrame = m_loopEnd * buffer()->sampleRate();
231
232 virtualMaxFrame = std::min(loopMaxFrame, virtualMaxFrame);
233 virtualMinFrame = std::max(loopMinFrame, virtualMinFrame);
234 virtualDeltaFrames = virtualMaxFrame - virtualMinFrame;
235 }
236
237
238 // Sanity check that our playback rate isn't larger than the loop size.
239 if (fabs(pitchRate) >= virtualDeltaFrames)
240 return false;
241
242 // Get local copy.
243 double virtualReadIndex = m_virtualReadIndex;
244
245 bool needsInterpolation = virtualReadIndex != floor(virtualReadIndex)
246 || virtualDeltaFrames != floor(virtualDeltaFrames)
247 || virtualMaxFrame != floor(virtualMaxFrame)
248 || virtualMinFrame != floor(virtualMinFrame);
249
250 // Render loop - reading from the source buffer to the destination using linear interpolation.
251 int framesToProcess = numberOfFrames;
252
253 const float** sourceChannels = m_sourceChannels.get();
254 float** destinationChannels = m_destinationChannels.get();
255
256 // Optimize for the very common case of playing back with pitchRate == 1.
257 // We can avoid the linear interpolation.
258 if (pitchRate == 1 && !needsInterpolation) {
259 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
260 unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames);
261 maxFrame = static_cast<unsigned>(virtualMaxFrame);
262 while (framesToProcess > 0) {
263 int framesToEnd = maxFrame - readIndex;
264 int framesThisTime = std::min(framesToProcess, framesToEnd);
265 framesThisTime = std::max(0, framesThisTime);
266
267 for (unsigned i = 0; i < numberOfChannels; ++i)
268 memcpy(destinationChannels[i] + writeIndex, sourceChannels[i] + readIndex, sizeof(float) * framesThisTime);
269
270 writeIndex += framesThisTime;
271 readIndex += framesThisTime;
272 framesToProcess -= framesThisTime;
273
274 // Wrap-around.
275 if (readIndex >= maxFrame) {
276 readIndex -= deltaFrames;
277 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
278 break;
279 }
280 }
281 virtualReadIndex = readIndex;
282 } else if (pitchRate == -1 && !needsInterpolation) {
283 int readIndex = static_cast<int>(virtualReadIndex);
284 int deltaFrames = static_cast<int>(virtualDeltaFrames);
285 int minFrame = static_cast<int>(virtualMinFrame) - 1;
286 while (framesToProcess > 0) {
287 int framesToEnd = readIndex - minFrame;
288 int framesThisTime = std::min<int>(framesToProcess, framesToEnd);
289 framesThisTime = std::max<int>(0, framesThisTime);
290
291 while (framesThisTime--) {
292 for (unsigned i = 0; i < numberOfChannels; ++i) {
293 float* destination = destinationChannels[i];
294 const float* source = sourceChannels[i];
295
296 destination[writeIndex] = source[readIndex];
297 }
298
299 ++writeIndex;
300 --readIndex;
301 --framesToProcess;
302 }
303
304 // Wrap-around.
305 if (readIndex <= minFrame) {
306 readIndex += deltaFrames;
307 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
308 break;
309 }
310 }
311 virtualReadIndex = readIndex;
312 } else if (!pitchRate) {
313 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
314
315 for (unsigned i = 0; i < numberOfChannels; ++i)
316 std::fill_n(destinationChannels[i], framesToProcess, sourceChannels[i][readIndex]);
317 } else if (reverse) {
318 unsigned maxFrame = static_cast<unsigned>(virtualMaxFrame);
319 unsigned minFrame = static_cast<unsigned>(floorf(virtualMinFrame));
320
321 while (framesToProcess--) {
322 unsigned readIndex = static_cast<unsigned>(floorf(virtualReadIndex));
323 double interpolationFactor = virtualReadIndex - readIndex;
324
325 unsigned readIndex2 = readIndex + 1;
326 if (readIndex2 >= maxFrame)
327 readIndex2 = loop() ? minFrame : maxFrame - 1;
328
329 // Linear interpolation.
330 for (unsigned i = 0; i < numberOfChannels; ++i) {
331 float* destination = destinationChannels[i];
332 const float* source = sourceChannels[i];
333
334 double sample1 = source[readIndex];
335 double sample2 = source[readIndex2];
336 double sample = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2;
337
338 destination[writeIndex] = narrowPrecisionToFloat(sample);
339 }
340
341 writeIndex++;
342
343 virtualReadIndex += pitchRate;
344
345 // Wrap-around, retaining sub-sample position since virtualReadIndex is floating-point.
346 if (virtualReadIndex < virtualMinFrame) {
347 virtualReadIndex += virtualDeltaFrames;
348 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
349 break;
350 }
351 }
352 } else {
353 while (framesToProcess--) {
354 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
355 double interpolationFactor = virtualReadIndex - readIndex;
356
357 // For linear interpolation we need the next sample-frame too.
358 unsigned readIndex2 = readIndex + 1;
359 if (readIndex2 >= bufferLength) {
360 if (loop()) {
361 // Make sure to wrap around at the end of the buffer.
362 readIndex2 = static_cast<unsigned>(virtualReadIndex + 1 - virtualDeltaFrames);
363 } else
364 readIndex2 = readIndex;
365 }
366
367 // Final sanity check on buffer access.
368 // FIXME: as an optimization, try to get rid of this inner-loop check and put assertions and guards before the loop.
369 if (readIndex >= bufferLength || readIndex2 >= bufferLength)
370 break;
371
372 // Linear interpolation.
373 for (unsigned i = 0; i < numberOfChannels; ++i) {
374 float* destination = destinationChannels[i];
375 const float* source = sourceChannels[i];
376
377 double sample1 = source[readIndex];
378 double sample2 = source[readIndex2];
379 double sample = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2;
380
381 destination[writeIndex] = narrowPrecisionToFloat(sample);
382 }
383 writeIndex++;
384
385 virtualReadIndex += pitchRate;
386
387 // Wrap-around, retaining sub-sample position since virtualReadIndex is floating-point.
388 if (virtualReadIndex >= virtualMaxFrame) {
389 virtualReadIndex -= virtualDeltaFrames;
390 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
391 break;
392 }
393 }
394 }
395
396 bus->clearSilentFlag();
397
398 m_virtualReadIndex = virtualReadIndex;
399
400 return true;
401}
402
403
404void AudioBufferSourceNode::reset()
405{
406 m_virtualReadIndex = 0;
407 m_lastGain = gain()->value();
408}
409
410void AudioBufferSourceNode::setBuffer(RefPtr<AudioBuffer>&& buffer)
411{
412 ASSERT(isMainThread());
413 DEBUG_LOG(LOGIDENTIFIER);
414
415 // The context must be locked since changing the buffer can re-configure the number of channels that are output.
416 AudioContext::AutoLocker contextLocker(context());
417
418 // This synchronizes with process().
419 std::lock_guard<Lock> lock(m_processMutex);
420
421 if (buffer) {
422 // Do any necesssary re-configuration to the buffer's number of channels.
423 unsigned numberOfChannels = buffer->numberOfChannels();
424 ASSERT(numberOfChannels <= AudioContext::maxNumberOfChannels());
425
426 output(0)->setNumberOfChannels(numberOfChannels);
427
428 m_sourceChannels = makeUniqueArray<const float*>(numberOfChannels);
429 m_destinationChannels = makeUniqueArray<float*>(numberOfChannels);
430
431 for (unsigned i = 0; i < numberOfChannels; ++i)
432 m_sourceChannels[i] = buffer->channelData(i)->data();
433 }
434
435 m_virtualReadIndex = 0;
436 m_buffer = WTFMove(buffer);
437}
438
439unsigned AudioBufferSourceNode::numberOfChannels()
440{
441 return output(0)->numberOfChannels();
442}
443
444ExceptionOr<void> AudioBufferSourceNode::start(double when, double grainOffset, Optional<double> optionalGrainDuration)
445{
446 double grainDuration = 0;
447 if (optionalGrainDuration)
448 grainDuration = optionalGrainDuration.value();
449 else if (buffer())
450 grainDuration = buffer()->duration() - grainOffset;
451
452 return startPlaying(Partial, when, grainOffset, grainDuration);
453}
454
455ExceptionOr<void> AudioBufferSourceNode::startPlaying(BufferPlaybackMode playbackMode, double when, double grainOffset, double grainDuration)
456{
457 ASSERT(isMainThread());
458 ALWAYS_LOG(LOGIDENTIFIER, "when = ", when, ", offset = ", grainOffset, ", duration = ", grainDuration);
459
460 context().nodeWillBeginPlayback();
461
462 if (m_playbackState != UNSCHEDULED_STATE)
463 return Exception { InvalidStateError };
464
465 if (!std::isfinite(when) || (when < 0))
466 return Exception { InvalidStateError };
467
468 if (!std::isfinite(grainOffset) || (grainOffset < 0))
469 return Exception { InvalidStateError };
470
471 if (!std::isfinite(grainDuration) || (grainDuration < 0))
472 return Exception { InvalidStateError };
473
474 if (!buffer())
475 return { };
476
477 m_isGrain = playbackMode == Partial;
478 if (m_isGrain) {
479 // Do sanity checking of grain parameters versus buffer size.
480 double bufferDuration = buffer()->duration();
481
482 m_grainOffset = std::min(bufferDuration, grainOffset);
483
484 double maxDuration = bufferDuration - m_grainOffset;
485 m_grainDuration = std::min(maxDuration, grainDuration);
486 } else {
487 m_grainOffset = 0.0;
488 m_grainDuration = buffer()->duration();
489 }
490
491 m_startTime = when;
492
493 // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation
494 // at a sub-sample position since it will degrade the quality.
495 // When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer.
496 // Since playbackRate == 1 is very common, it's worth considering quality.
497 if (totalPitchRate() < 0)
498 m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, buffer()->sampleRate()) - 1;
499 else
500 m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer()->sampleRate());
501
502 m_playbackState = SCHEDULED_STATE;
503
504 return { };
505}
506
507double AudioBufferSourceNode::totalPitchRate()
508{
509 double dopplerRate = 1.0;
510 if (m_pannerNode)
511 dopplerRate = m_pannerNode->dopplerRate();
512
513 // Incorporate buffer's sample-rate versus AudioContext's sample-rate.
514 // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case.
515 double sampleRateFactor = 1.0;
516 if (buffer())
517 sampleRateFactor = buffer()->sampleRate() / sampleRate();
518
519 double basePitchRate = playbackRate()->value();
520
521 double totalRate = dopplerRate * sampleRateFactor * basePitchRate;
522
523 totalRate = std::max(-MaxRate, std::min(MaxRate, totalRate));
524
525 bool isTotalRateValid = !std::isnan(totalRate) && !std::isinf(totalRate);
526 ASSERT(isTotalRateValid);
527 if (!isTotalRateValid)
528 totalRate = 1.0;
529
530 return totalRate;
531}
532
533bool AudioBufferSourceNode::looping()
534{
535 static bool firstTime = true;
536 if (firstTime) {
537 context().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, "AudioBufferSourceNode 'looping' attribute is deprecated. Use 'loop' instead."_s);
538 firstTime = false;
539 }
540
541 return m_isLooping;
542}
543
544void AudioBufferSourceNode::setLooping(bool looping)
545{
546 static bool firstTime = true;
547 if (firstTime) {
548 context().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, "AudioBufferSourceNode 'looping' attribute is deprecated. Use 'loop' instead."_s);
549 firstTime = false;
550 }
551
552 m_isLooping = looping;
553}
554
555bool AudioBufferSourceNode::propagatesSilence() const
556{
557 return !isPlayingOrScheduled() || hasFinished() || !m_buffer;
558}
559
560void AudioBufferSourceNode::setPannerNode(PannerNode* pannerNode)
561{
562 if (m_pannerNode != pannerNode && !hasFinished()) {
563 if (pannerNode)
564 pannerNode->ref(AudioNode::RefTypeConnection);
565 if (m_pannerNode)
566 m_pannerNode->deref(AudioNode::RefTypeConnection);
567
568 m_pannerNode = pannerNode;
569 }
570}
571
572void AudioBufferSourceNode::clearPannerNode()
573{
574 if (m_pannerNode) {
575 m_pannerNode->deref(AudioNode::RefTypeConnection);
576 m_pannerNode = nullptr;
577 }
578}
579
580void AudioBufferSourceNode::finish()
581{
582 clearPannerNode();
583 ASSERT(!m_pannerNode);
584 AudioScheduledSourceNode::finish();
585}
586
587} // namespace WebCore
588
589#endif // ENABLE(WEB_AUDIO)
590