2 * Copyright (C) 2010, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "modules/webaudio/AudioBufferSourceNode.h"
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"
43 const double DefaultGrainDuration = 0.020; // 20ms
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;
50 PassRefPtrWillBeRawPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, float sampleRate)
52 return adoptRefWillBeNoop(new AudioBufferSourceNode(context, sampleRate));
55 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* context, float sampleRate)
56 : AudioScheduledSourceNode(context, sampleRate)
61 , m_virtualReadIndex(0)
64 , m_grainDuration(DefaultGrainDuration)
66 ScriptWrappable::init(this);
67 setNodeType(NodeTypeAudioBufferSource);
69 m_playbackRate = AudioParam::create(context, 1.0);
71 // Default to mono. A call to setBuffer() will set the number of output
72 // channels to that of the buffer.
73 addOutput(AudioNodeOutput::create(this, 1));
78 AudioBufferSourceNode::~AudioBufferSourceNode()
80 ASSERT(!isInitialized());
83 void AudioBufferSourceNode::dispose()
87 AudioScheduledSourceNode::dispose();
90 void AudioBufferSourceNode::process(size_t framesToProcess)
92 AudioBus* outputBus = output(0)->bus();
94 if (!isInitialized()) {
99 // The audio thread can't block on this lock, so we call tryLock() instead.
100 MutexTryLocker tryLocker(m_processLock);
101 if (tryLocker.locked()) {
107 // After calling setBuffer() with a buffer having a different number of channels, there can in rare cases be a slight delay
108 // before the output bus is updated to the new number of channels because of use of tryLocks() in the context's updating system.
109 // In this case, if the the buffer has just been changed and we're not quite ready yet, then just output silence.
110 if (numberOfChannels() != buffer()->numberOfChannels()) {
115 size_t quantumFrameOffset;
116 size_t bufferFramesToProcess;
118 updateSchedulingInfo(framesToProcess,
121 bufferFramesToProcess);
123 if (!bufferFramesToProcess) {
128 for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i)
129 m_destinationChannels[i] = outputBus->channel(i)->mutableData();
131 // Render by reading directly from the buffer.
132 if (!renderFromBuffer(outputBus, quantumFrameOffset, bufferFramesToProcess)) {
137 outputBus->clearSilentFlag();
139 // Too bad - the tryLock() failed. We must be in the middle of changing buffers and were already outputting silence anyway.
144 // Returns true if we're finished.
145 bool AudioBufferSourceNode::renderSilenceAndFinishIfNotLooping(AudioBus*, unsigned index, size_t framesToProcess)
148 // If we're not looping, then stop playing when we get to the end.
150 if (framesToProcess > 0) {
151 // We're not looping and we've reached the end of the sample data, but we still need to provide more output,
152 // so generate silence for the remaining.
153 for (unsigned i = 0; i < numberOfChannels(); ++i)
154 memset(m_destinationChannels[i] + index, 0, sizeof(float) * framesToProcess);
163 bool AudioBufferSourceNode::renderFromBuffer(AudioBus* bus, unsigned destinationFrameOffset, size_t numberOfFrames)
165 ASSERT(context()->isAudioThread());
167 // Basic sanity checking
170 if (!bus || !buffer())
173 unsigned numberOfChannels = this->numberOfChannels();
174 unsigned busNumberOfChannels = bus->numberOfChannels();
176 bool channelCountGood = numberOfChannels && numberOfChannels == busNumberOfChannels;
177 ASSERT(channelCountGood);
178 if (!channelCountGood)
181 // Sanity check destinationFrameOffset, numberOfFrames.
182 size_t destinationLength = bus->length();
184 bool isLengthGood = destinationLength <= 4096 && numberOfFrames <= 4096;
185 ASSERT(isLengthGood);
189 bool isOffsetGood = destinationFrameOffset <= destinationLength && destinationFrameOffset + numberOfFrames <= destinationLength;
190 ASSERT(isOffsetGood);
194 // Potentially zero out initial frames leading up to the offset.
195 if (destinationFrameOffset) {
196 for (unsigned i = 0; i < numberOfChannels; ++i)
197 memset(m_destinationChannels[i], 0, sizeof(float) * destinationFrameOffset);
200 // Offset the pointers to the correct offset frame.
201 unsigned writeIndex = destinationFrameOffset;
203 size_t bufferLength = buffer()->length();
204 double bufferSampleRate = buffer()->sampleRate();
206 // Avoid converting from time to sample-frames twice by computing
207 // the grain end time first before computing the sample frame.
208 unsigned endFrame = m_isGrain ? AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, bufferSampleRate) : bufferLength;
210 // This is a HACK to allow for HRTF tail-time - avoids glitch at end.
211 // FIXME: implement tailTime for each AudioNode for a more general solution to this problem.
212 // https://bugs.webkit.org/show_bug.cgi?id=77224
216 // Do some sanity checking.
217 if (endFrame > bufferLength)
218 endFrame = bufferLength;
219 if (m_virtualReadIndex >= endFrame)
220 m_virtualReadIndex = 0; // reset to start
222 // If the .loop attribute is true, then values of m_loopStart == 0 && m_loopEnd == 0 implies
223 // that we should use the entire buffer as the loop, otherwise use the loop values in m_loopStart and m_loopEnd.
224 double virtualEndFrame = endFrame;
225 double virtualDeltaFrames = endFrame;
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 loopStartFrame = m_loopStart * buffer()->sampleRate();
230 double loopEndFrame = m_loopEnd * buffer()->sampleRate();
232 virtualEndFrame = std::min(loopEndFrame, virtualEndFrame);
233 virtualDeltaFrames = virtualEndFrame - loopStartFrame;
237 double pitchRate = totalPitchRate();
239 // Sanity check that our playback rate isn't larger than the loop size.
240 if (pitchRate >= virtualDeltaFrames)
244 double virtualReadIndex = m_virtualReadIndex;
246 // Render loop - reading from the source buffer to the destination using linear interpolation.
247 int framesToProcess = numberOfFrames;
249 const float** sourceChannels = m_sourceChannels.get();
250 float** destinationChannels = m_destinationChannels.get();
252 // Optimize for the very common case of playing back with pitchRate == 1.
253 // We can avoid the linear interpolation.
254 if (pitchRate == 1 && virtualReadIndex == floor(virtualReadIndex)
255 && virtualDeltaFrames == floor(virtualDeltaFrames)
256 && virtualEndFrame == floor(virtualEndFrame)) {
257 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
258 unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames);
259 endFrame = static_cast<unsigned>(virtualEndFrame);
260 while (framesToProcess > 0) {
261 int framesToEnd = endFrame - readIndex;
262 int framesThisTime = std::min(framesToProcess, framesToEnd);
263 framesThisTime = std::max(0, framesThisTime);
265 for (unsigned i = 0; i < numberOfChannels; ++i)
266 memcpy(destinationChannels[i] + writeIndex, sourceChannels[i] + readIndex, sizeof(float) * framesThisTime);
268 writeIndex += framesThisTime;
269 readIndex += framesThisTime;
270 framesToProcess -= framesThisTime;
273 if (readIndex >= endFrame) {
274 readIndex -= deltaFrames;
275 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
279 virtualReadIndex = readIndex;
281 while (framesToProcess--) {
282 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
283 double interpolationFactor = virtualReadIndex - readIndex;
285 // For linear interpolation we need the next sample-frame too.
286 unsigned readIndex2 = readIndex + 1;
287 if (readIndex2 >= bufferLength) {
289 // Make sure to wrap around at the end of the buffer.
290 readIndex2 = static_cast<unsigned>(virtualReadIndex + 1 - virtualDeltaFrames);
292 readIndex2 = readIndex;
295 // Final sanity check on buffer access.
296 // FIXME: as an optimization, try to get rid of this inner-loop check and put assertions and guards before the loop.
297 if (readIndex >= bufferLength || readIndex2 >= bufferLength)
300 // Linear interpolation.
301 for (unsigned i = 0; i < numberOfChannels; ++i) {
302 float* destination = destinationChannels[i];
303 const float* source = sourceChannels[i];
305 double sample1 = source[readIndex];
306 double sample2 = source[readIndex2];
307 double sample = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2;
309 destination[writeIndex] = narrowPrecisionToFloat(sample);
313 virtualReadIndex += pitchRate;
315 // Wrap-around, retaining sub-sample position since virtualReadIndex is floating-point.
316 if (virtualReadIndex >= virtualEndFrame) {
317 virtualReadIndex -= virtualDeltaFrames;
318 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
324 bus->clearSilentFlag();
326 m_virtualReadIndex = virtualReadIndex;
332 void AudioBufferSourceNode::setBuffer(AudioBuffer* buffer, ExceptionState& exceptionState)
334 ASSERT(isMainThread());
336 // The context must be locked since changing the buffer can re-configure the number of channels that are output.
337 AudioContext::AutoLocker contextLocker(context());
339 // This synchronizes with process().
340 MutexLocker processLocker(m_processLock);
343 // Do any necesssary re-configuration to the buffer's number of channels.
344 unsigned numberOfChannels = buffer->numberOfChannels();
346 if (numberOfChannels > AudioContext::maxNumberOfChannels()) {
347 exceptionState.throwTypeError("number of input channels (" + String::number(numberOfChannels)
348 + ") exceeds maximum ("
349 + String::number(AudioContext::maxNumberOfChannels()) + ").");
353 output(0)->setNumberOfChannels(numberOfChannels);
355 m_sourceChannels = adoptArrayPtr(new const float* [numberOfChannels]);
356 m_destinationChannels = adoptArrayPtr(new float* [numberOfChannels]);
358 for (unsigned i = 0; i < numberOfChannels; ++i)
359 m_sourceChannels[i] = buffer->getChannelData(i)->data();
362 m_virtualReadIndex = 0;
366 unsigned AudioBufferSourceNode::numberOfChannels()
368 return output(0)->numberOfChannels();
371 void AudioBufferSourceNode::start(double when, ExceptionState& exceptionState)
373 AudioScheduledSourceNode::start(when, exceptionState);
376 void AudioBufferSourceNode::start(double when, double grainOffset, ExceptionState& exceptionState)
378 start(when, grainOffset, buffer() ? buffer()->duration() : 0, exceptionState);
381 void AudioBufferSourceNode::start(double when, double grainOffset, double grainDuration, ExceptionState& exceptionState)
383 ASSERT(isMainThread());
385 if (m_playbackState != UNSCHEDULED_STATE) {
386 exceptionState.throwDOMException(
388 "cannot call start more than once.");
395 // Do sanity checking of grain parameters versus buffer size.
396 double bufferDuration = buffer()->duration();
398 grainOffset = std::max(0.0, grainOffset);
399 grainOffset = std::min(bufferDuration, grainOffset);
400 m_grainOffset = grainOffset;
402 double maxDuration = bufferDuration - grainOffset;
404 grainDuration = std::max(0.0, grainDuration);
405 grainDuration = std::min(maxDuration, grainDuration);
406 m_grainDuration = grainDuration;
411 // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation
412 // at a sub-sample position since it will degrade the quality.
413 // When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer.
414 // Since playbackRate == 1 is very common, it's worth considering quality.
415 m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer()->sampleRate());
417 m_playbackState = SCHEDULED_STATE;
420 double AudioBufferSourceNode::totalPitchRate()
422 double dopplerRate = 1.0;
424 dopplerRate = m_pannerNode->dopplerRate();
426 // Incorporate buffer's sample-rate versus AudioContext's sample-rate.
427 // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case.
428 double sampleRateFactor = 1.0;
430 sampleRateFactor = buffer()->sampleRate() / sampleRate();
432 double basePitchRate = playbackRate()->value();
434 double totalRate = dopplerRate * sampleRateFactor * basePitchRate;
436 // Sanity check the total rate. It's very important that the resampler not get any bad rate values.
437 totalRate = std::max(0.0, totalRate);
439 totalRate = 1; // zero rate is considered illegal
440 totalRate = std::min(MaxRate, totalRate);
442 bool isTotalRateValid = !std::isnan(totalRate) && !std::isinf(totalRate);
443 ASSERT(isTotalRateValid);
444 if (!isTotalRateValid)
450 bool AudioBufferSourceNode::propagatesSilence() const
452 return !isPlayingOrScheduled() || hasFinished() || !m_buffer;
455 void AudioBufferSourceNode::setPannerNode(PannerNode* pannerNode)
457 if (m_pannerNode != pannerNode && !hasFinished()) {
458 RefPtrWillBeRawPtr<PannerNode> oldPannerNode(m_pannerNode.release());
459 m_pannerNode = pannerNode;
461 pannerNode->makeConnection();
463 oldPannerNode->breakConnection();
467 void AudioBufferSourceNode::clearPannerNode()
470 m_pannerNode->breakConnection();
471 m_pannerNode.clear();
475 void AudioBufferSourceNode::finish()
478 ASSERT(!m_pannerNode);
479 AudioScheduledSourceNode::finish();
482 void AudioBufferSourceNode::trace(Visitor* visitor)
484 visitor->trace(m_buffer);
485 visitor->trace(m_playbackRate);
486 visitor->trace(m_pannerNode);
487 AudioScheduledSourceNode::trace(visitor);
492 #endif // ENABLE(WEB_AUDIO)