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 "AudioBufferSourceNode.h"
31 #include "AudioContext.h"
32 #include "AudioNodeOutput.h"
33 #include "AudioUtilities.h"
34 #include "FloatConversion.h"
35 #include "ScriptCallStack.h"
36 #include "ScriptExecutionContext.h"
38 #include <wtf/MainThread.h>
39 #include <wtf/MathExtras.h>
45 const double DefaultGrainDuration = 0.020; // 20ms
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;
52 PassRefPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, float sampleRate)
54 return adoptRef(new AudioBufferSourceNode(context, sampleRate));
57 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* context, float sampleRate)
58 : AudioScheduledSourceNode(context, sampleRate)
63 , m_virtualReadIndex(0)
66 , m_grainDuration(DefaultGrainDuration)
70 setNodeType(NodeTypeAudioBufferSource);
72 m_gain = AudioGain::create(context, "gain", 1.0, 0.0, 1.0);
73 m_playbackRate = AudioParam::create(context, "playbackRate", 1.0, 0.0, MaxRate);
75 // Default to mono. A call to setBuffer() will set the number of output channels to that of the buffer.
76 addOutput(adoptPtr(new AudioNodeOutput(this, 1)));
81 AudioBufferSourceNode::~AudioBufferSourceNode()
87 void AudioBufferSourceNode::process(size_t framesToProcess)
89 AudioBus* outputBus = output(0)->bus();
91 if (!isInitialized()) {
96 // The audio thread can't block on this lock, so we call tryLock() instead.
97 MutexTryLocker tryLocker(m_processLock);
98 if (tryLocker.locked()) {
104 size_t quantumFrameOffset;
105 size_t bufferFramesToProcess;
107 updateSchedulingInfo(framesToProcess,
110 bufferFramesToProcess);
112 if (!bufferFramesToProcess) {
117 for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i)
118 m_destinationChannels[i] = outputBus->channel(i)->mutableData();
120 // Render by reading directly from the buffer.
121 if (!renderFromBuffer(outputBus, quantumFrameOffset, bufferFramesToProcess)) {
126 // Apply the gain (in-place) to the output bus.
127 float totalGain = gain()->value() * m_buffer->gain();
128 outputBus->copyWithGainFrom(*outputBus, &m_lastGain, totalGain);
129 outputBus->clearSilentFlag();
131 // Too bad - the tryLock() failed. We must be in the middle of changing buffers and were already outputting silence anyway.
136 // Returns true if we're finished.
137 bool AudioBufferSourceNode::renderSilenceAndFinishIfNotLooping(AudioBus*, unsigned index, size_t framesToProcess)
140 // If we're not looping, then stop playing when we get to the end.
142 if (framesToProcess > 0) {
143 // We're not looping and we've reached the end of the sample data, but we still need to provide more output,
144 // so generate silence for the remaining.
145 for (unsigned i = 0; i < numberOfChannels(); ++i)
146 memset(m_destinationChannels[i] + index, 0, sizeof(float) * framesToProcess);
155 bool AudioBufferSourceNode::renderFromBuffer(AudioBus* bus, unsigned destinationFrameOffset, size_t numberOfFrames)
157 ASSERT(context()->isAudioThread());
159 // Basic sanity checking
162 if (!bus || !buffer())
165 unsigned numberOfChannels = this->numberOfChannels();
166 unsigned busNumberOfChannels = bus->numberOfChannels();
168 bool channelCountGood = numberOfChannels && numberOfChannels == busNumberOfChannels;
169 ASSERT(channelCountGood);
170 if (!channelCountGood)
173 // Sanity check destinationFrameOffset, numberOfFrames.
174 size_t destinationLength = bus->length();
176 bool isLengthGood = destinationLength <= 4096 && numberOfFrames <= 4096;
177 ASSERT(isLengthGood);
181 bool isOffsetGood = destinationFrameOffset <= destinationLength && destinationFrameOffset + numberOfFrames <= destinationLength;
182 ASSERT(isOffsetGood);
186 // Potentially zero out initial frames leading up to the offset.
187 if (destinationFrameOffset) {
188 for (unsigned i = 0; i < numberOfChannels; ++i)
189 memset(m_destinationChannels[i], 0, sizeof(float) * destinationFrameOffset);
192 // Offset the pointers to the correct offset frame.
193 unsigned writeIndex = destinationFrameOffset;
195 size_t bufferLength = buffer()->length();
196 double bufferSampleRate = buffer()->sampleRate();
198 // Avoid converting from time to sample-frames twice by computing
199 // the grain end time first before computing the sample frame.
200 unsigned endFrame = m_isGrain ? AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, bufferSampleRate) : bufferLength;
202 // This is a HACK to allow for HRTF tail-time - avoids glitch at end.
203 // FIXME: implement tailTime for each AudioNode for a more general solution to this problem.
204 // https://bugs.webkit.org/show_bug.cgi?id=77224
208 // Do some sanity checking.
209 if (endFrame > bufferLength)
210 endFrame = bufferLength;
211 if (m_virtualReadIndex >= endFrame)
212 m_virtualReadIndex = 0; // reset to start
214 // If the .loop attribute is true, then values of m_loopStart == 0 && m_loopEnd == 0 implies
215 // that we should use the entire buffer as the loop, otherwise use the loop values in m_loopStart and m_loopEnd.
216 double virtualEndFrame = endFrame;
217 double virtualDeltaFrames = endFrame;
219 if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 && m_loopEnd > 0 && m_loopStart < m_loopEnd) {
220 // Convert from seconds to sample-frames.
221 double loopStartFrame = m_loopStart * buffer()->sampleRate();
222 double loopEndFrame = m_loopEnd * buffer()->sampleRate();
224 virtualEndFrame = min(loopEndFrame, virtualEndFrame);
225 virtualDeltaFrames = virtualEndFrame - loopStartFrame;
229 double pitchRate = totalPitchRate();
231 // Sanity check that our playback rate isn't larger than the loop size.
232 if (pitchRate >= virtualDeltaFrames)
236 double virtualReadIndex = m_virtualReadIndex;
238 // Render loop - reading from the source buffer to the destination using linear interpolation.
239 int framesToProcess = numberOfFrames;
241 const float** sourceChannels = m_sourceChannels.get();
242 float** destinationChannels = m_destinationChannels.get();
244 // Optimize for the very common case of playing back with pitchRate == 1.
245 // We can avoid the linear interpolation.
246 if (pitchRate == 1 && virtualReadIndex == floor(virtualReadIndex)
247 && virtualDeltaFrames == floor(virtualDeltaFrames)
248 && virtualEndFrame == floor(virtualEndFrame)) {
249 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
250 unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames);
251 endFrame = static_cast<unsigned>(virtualEndFrame);
252 while (framesToProcess > 0) {
253 int framesToEnd = endFrame - readIndex;
254 int framesThisTime = min(framesToProcess, framesToEnd);
255 framesThisTime = max(0, framesThisTime);
257 for (unsigned i = 0; i < numberOfChannels; ++i)
258 memcpy(destinationChannels[i] + writeIndex, sourceChannels[i] + readIndex, sizeof(float) * framesThisTime);
260 writeIndex += framesThisTime;
261 readIndex += framesThisTime;
262 framesToProcess -= framesThisTime;
265 if (readIndex >= endFrame) {
266 readIndex -= deltaFrames;
267 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
271 virtualReadIndex = readIndex;
273 while (framesToProcess--) {
274 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
275 double interpolationFactor = virtualReadIndex - readIndex;
277 // For linear interpolation we need the next sample-frame too.
278 unsigned readIndex2 = readIndex + 1;
279 if (readIndex2 >= bufferLength) {
281 // Make sure to wrap around at the end of the buffer.
282 readIndex2 = static_cast<unsigned>(virtualReadIndex + 1 - virtualDeltaFrames);
284 readIndex2 = readIndex;
287 // Final sanity check on buffer access.
288 // FIXME: as an optimization, try to get rid of this inner-loop check and put assertions and guards before the loop.
289 if (readIndex >= bufferLength || readIndex2 >= bufferLength)
292 // Linear interpolation.
293 for (unsigned i = 0; i < numberOfChannels; ++i) {
294 float* destination = destinationChannels[i];
295 const float* source = sourceChannels[i];
297 double sample1 = source[readIndex];
298 double sample2 = source[readIndex2];
299 double sample = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2;
301 destination[writeIndex] = narrowPrecisionToFloat(sample);
305 virtualReadIndex += pitchRate;
307 // Wrap-around, retaining sub-sample position since virtualReadIndex is floating-point.
308 if (virtualReadIndex >= virtualEndFrame) {
309 virtualReadIndex -= virtualDeltaFrames;
310 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
316 bus->clearSilentFlag();
318 m_virtualReadIndex = virtualReadIndex;
324 void AudioBufferSourceNode::reset()
326 m_virtualReadIndex = 0;
327 m_lastGain = gain()->value();
330 bool AudioBufferSourceNode::setBuffer(AudioBuffer* buffer)
332 ASSERT(isMainThread());
334 // The context must be locked since changing the buffer can re-configure the number of channels that are output.
335 AudioContext::AutoLocker contextLocker(context());
337 // This synchronizes with process().
338 MutexLocker processLocker(m_processLock);
341 // Do any necesssary re-configuration to the buffer's number of channels.
342 unsigned numberOfChannels = buffer->numberOfChannels();
344 if (numberOfChannels > AudioContext::maxNumberOfChannels())
347 output(0)->setNumberOfChannels(numberOfChannels);
349 m_sourceChannels = adoptArrayPtr(new const float* [numberOfChannels]);
350 m_destinationChannels = adoptArrayPtr(new float* [numberOfChannels]);
352 for (unsigned i = 0; i < numberOfChannels; ++i)
353 m_sourceChannels[i] = buffer->getChannelData(i)->data();
356 m_virtualReadIndex = 0;
362 unsigned AudioBufferSourceNode::numberOfChannels()
364 return output(0)->numberOfChannels();
367 #if defined(ENABLE_TIZEN_WEB_AUDIO) || defined(ENABLE_WEB_AUDIO)
368 void AudioBufferSourceNode::noteGrainOn(double when, double grainOffset, double grainDuration, ExceptionCode& ec)
370 void AudioBufferSourceNode::noteGrainOn(double when, double grainOffset, double grainDuration)
373 ASSERT(isMainThread());
375 if (m_playbackState != UNSCHEDULED_STATE)
376 #if defined(ENABLE_TIZEN_WEB_AUDIO) || defined(ENABLE_WEB_AUDIO)
378 ec = INVALID_STATE_ERR;
388 // Do sanity checking of grain parameters versus buffer size.
389 double bufferDuration = buffer()->duration();
391 if (grainDuration > bufferDuration)
392 return; // FIXME: maybe should throw exception - consider in specification.
394 double maxGrainOffset = bufferDuration - grainDuration;
395 maxGrainOffset = max(0.0, maxGrainOffset);
397 grainOffset = max(0.0, grainOffset);
398 grainOffset = min(maxGrainOffset, grainOffset);
399 m_grainOffset = grainOffset;
401 m_grainDuration = grainDuration;
406 // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation
407 // at a sub-sample position since it will degrade the quality.
408 // When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer.
409 // Since playbackRate == 1 is very common, it's worth considering quality.
410 m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer()->sampleRate());
412 m_playbackState = SCHEDULED_STATE;
415 double AudioBufferSourceNode::totalPitchRate()
417 double dopplerRate = 1.0;
419 dopplerRate = m_pannerNode->dopplerRate();
421 // Incorporate buffer's sample-rate versus AudioContext's sample-rate.
422 // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case.
423 double sampleRateFactor = 1.0;
425 sampleRateFactor = buffer()->sampleRate() / sampleRate();
427 double basePitchRate = playbackRate()->value();
429 double totalRate = dopplerRate * sampleRateFactor * basePitchRate;
431 // Sanity check the total rate. It's very important that the resampler not get any bad rate values.
432 totalRate = max(0.0, totalRate);
434 totalRate = 1; // zero rate is considered illegal
435 totalRate = min(MaxRate, totalRate);
437 bool isTotalRateValid = !isnan(totalRate) && !isinf(totalRate);
438 ASSERT(isTotalRateValid);
439 if (!isTotalRateValid)
445 bool AudioBufferSourceNode::looping()
447 static bool firstTime = true;
448 if (firstTime && context() && context()->scriptExecutionContext()) {
449 context()->scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, WarningMessageLevel, "AudioBufferSourceNode 'looping' attribute is deprecated. Use 'loop' instead.");
456 void AudioBufferSourceNode::setLooping(bool looping)
458 static bool firstTime = true;
459 if (firstTime && context() && context()->scriptExecutionContext()) {
460 context()->scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, WarningMessageLevel, "AudioBufferSourceNode 'looping' attribute is deprecated. Use 'loop' instead.");
464 m_isLooping = looping;
467 bool AudioBufferSourceNode::propagatesSilence() const
469 return !isPlayingOrScheduled() || hasFinished() || !m_buffer;
472 void AudioBufferSourceNode::setPannerNode(AudioPannerNode* pannerNode)
474 if (m_pannerNode != pannerNode && !hasFinished()) {
476 pannerNode->ref(AudioNode::RefTypeConnection);
478 m_pannerNode->deref(AudioNode::RefTypeConnection);
480 m_pannerNode = pannerNode;
484 void AudioBufferSourceNode::clearPannerNode()
487 m_pannerNode->deref(AudioNode::RefTypeConnection);
492 void AudioBufferSourceNode::finish()
495 ASSERT(!m_pannerNode);
496 AudioScheduledSourceNode::finish();
499 } // namespace WebCore
501 #endif // ENABLE(WEB_AUDIO)