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 52 PassRefPtrWillBeRawPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, float sampleRate) 53 { 54 return adoptRefWillBeNoop(new AudioBufferSourceNode(context, sampleRate)); 55 } 56 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 80 AudioBufferSourceNode::~AudioBufferSourceNode() 81 { 82 clearPannerNode(); 83 uninitialize(); 84 } 85 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. 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 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 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 362 unsigned AudioBufferSourceNode::numberOfChannels() 363 { 364 return output(0)->numberOfChannels(); 365 } 366 367 void AudioBufferSourceNode::start(double when, ExceptionState& exceptionState) 368 { 369 AudioScheduledSourceNode::start(when, exceptionState); 370 } 371 372 void AudioBufferSourceNode::start(double when, double grainOffset, ExceptionState& exceptionState) 373 { 374 start(when, grainOffset, buffer() ? buffer()->duration() : 0, exceptionState); 375 } 376 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 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 446 bool AudioBufferSourceNode::propagatesSilence() const 447 { 448 return !isPlayingOrScheduled() || hasFinished() || !m_buffer; 449 } 450 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 463 void AudioBufferSourceNode::clearPannerNode() 464 { 465 if (m_pannerNode) { 466 m_pannerNode->deref(AudioNode::RefTypeConnection); 467 m_pannerNode = 0; 468 } 469 } 470 471 void AudioBufferSourceNode::finish() 472 { 473 clearPannerNode(); 474 ASSERT(!m_pannerNode); 475 AudioScheduledSourceNode::finish(); 476 } 477 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