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 "core/page/PageConsole.h" 34 #include "platform/audio/AudioUtilities.h" 35 #include "modules/webaudio/AudioContext.h" 36 #include "modules/webaudio/AudioNodeOutput.h" 37 #include "platform/FloatConversion.h" 38 #include "wtf/MainThread.h" 39 #include "wtf/MathExtras.h" 40 #include <algorithm> 41 42 using namespace std; 43 44 namespace WebCore { 45 46 const double DefaultGrainDuration = 0.020; // 20ms 47 48 // Arbitrary upper limit on playback rate. 49 // Higher than expected rates can be useful when playing back oversampled buffers 50 // to minimize linear interpolation aliasing. 51 const double MaxRate = 1024; 52 53 PassRefPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, float sampleRate) 54 { 55 return adoptRef(new AudioBufferSourceNode(context, sampleRate)); 56 } 57 58 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* context, float sampleRate) 59 : AudioScheduledSourceNode(context, sampleRate) 60 , m_buffer(0) 61 , m_isLooping(false) 62 , m_loopStart(0) 63 , m_loopEnd(0) 64 , m_virtualReadIndex(0) 65 , m_isGrain(false) 66 , m_grainOffset(0.0) 67 , m_grainDuration(DefaultGrainDuration) 68 , m_lastGain(1.0) 69 , m_pannerNode(0) 70 { 71 ScriptWrappable::init(this); 72 setNodeType(NodeTypeAudioBufferSource); 73 74 m_gain = AudioParam::create(context, "gain", 1.0, 0.0, 1.0); 75 m_playbackRate = AudioParam::create(context, "playbackRate", 1.0, 0.0, MaxRate); 76 77 // Default to mono. A call to setBuffer() will set the number of output channels to that of the buffer. 78 addOutput(adoptPtr(new AudioNodeOutput(this, 1))); 79 80 initialize(); 81 } 82 83 AudioBufferSourceNode::~AudioBufferSourceNode() 84 { 85 clearPannerNode(); 86 uninitialize(); 87 } 88 89 void AudioBufferSourceNode::process(size_t framesToProcess) 90 { 91 AudioBus* outputBus = output(0)->bus(); 92 93 if (!isInitialized()) { 94 outputBus->zero(); 95 return; 96 } 97 98 // The audio thread can't block on this lock, so we call tryLock() instead. 99 MutexTryLocker tryLocker(m_processLock); 100 if (tryLocker.locked()) { 101 if (!buffer()) { 102 outputBus->zero(); 103 return; 104 } 105 106 // After calling setBuffer() with a buffer having a different number of channels, there can in rare cases be a slight delay 107 // before the output bus is updated to the new number of channels because of use of tryLocks() in the context's updating system. 108 // In this case, if the the buffer has just been changed and we're not quite ready yet, then just output silence. 109 if (numberOfChannels() != buffer()->numberOfChannels()) { 110 outputBus->zero(); 111 return; 112 } 113 114 size_t quantumFrameOffset; 115 size_t bufferFramesToProcess; 116 117 updateSchedulingInfo(framesToProcess, 118 outputBus, 119 quantumFrameOffset, 120 bufferFramesToProcess); 121 122 if (!bufferFramesToProcess) { 123 outputBus->zero(); 124 return; 125 } 126 127 for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i) 128 m_destinationChannels[i] = outputBus->channel(i)->mutableData(); 129 130 // Render by reading directly from the buffer. 131 if (!renderFromBuffer(outputBus, quantumFrameOffset, bufferFramesToProcess)) { 132 outputBus->zero(); 133 return; 134 } 135 136 // Apply the gain (in-place) to the output bus. 137 float totalGain = gain()->value() * m_buffer->gain(); 138 outputBus->copyWithGainFrom(*outputBus, &m_lastGain, totalGain); 139 outputBus->clearSilentFlag(); 140 } else { 141 // Too bad - the tryLock() failed. We must be in the middle of changing buffers and were already outputting silence anyway. 142 outputBus->zero(); 143 } 144 } 145 146 // Returns true if we're finished. 147 bool AudioBufferSourceNode::renderSilenceAndFinishIfNotLooping(AudioBus*, unsigned index, size_t framesToProcess) 148 { 149 if (!loop()) { 150 // If we're not looping, then stop playing when we get to the end. 151 152 if (framesToProcess > 0) { 153 // We're not looping and we've reached the end of the sample data, but we still need to provide more output, 154 // so generate silence for the remaining. 155 for (unsigned i = 0; i < numberOfChannels(); ++i) 156 memset(m_destinationChannels[i] + index, 0, sizeof(float) * framesToProcess); 157 } 158 159 finish(); 160 return true; 161 } 162 return false; 163 } 164 165 bool AudioBufferSourceNode::renderFromBuffer(AudioBus* bus, unsigned destinationFrameOffset, size_t numberOfFrames) 166 { 167 ASSERT(context()->isAudioThread()); 168 169 // Basic sanity checking 170 ASSERT(bus); 171 ASSERT(buffer()); 172 if (!bus || !buffer()) 173 return false; 174 175 unsigned numberOfChannels = this->numberOfChannels(); 176 unsigned busNumberOfChannels = bus->numberOfChannels(); 177 178 bool channelCountGood = numberOfChannels && numberOfChannels == busNumberOfChannels; 179 ASSERT(channelCountGood); 180 if (!channelCountGood) 181 return false; 182 183 // Sanity check destinationFrameOffset, numberOfFrames. 184 size_t destinationLength = bus->length(); 185 186 bool isLengthGood = destinationLength <= 4096 && numberOfFrames <= 4096; 187 ASSERT(isLengthGood); 188 if (!isLengthGood) 189 return false; 190 191 bool isOffsetGood = destinationFrameOffset <= destinationLength && destinationFrameOffset + numberOfFrames <= destinationLength; 192 ASSERT(isOffsetGood); 193 if (!isOffsetGood) 194 return false; 195 196 // Potentially zero out initial frames leading up to the offset. 197 if (destinationFrameOffset) { 198 for (unsigned i = 0; i < numberOfChannels; ++i) 199 memset(m_destinationChannels[i], 0, sizeof(float) * destinationFrameOffset); 200 } 201 202 // Offset the pointers to the correct offset frame. 203 unsigned writeIndex = destinationFrameOffset; 204 205 size_t bufferLength = buffer()->length(); 206 double bufferSampleRate = buffer()->sampleRate(); 207 208 // Avoid converting from time to sample-frames twice by computing 209 // the grain end time first before computing the sample frame. 210 unsigned endFrame = m_isGrain ? AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, bufferSampleRate) : bufferLength; 211 212 // This is a HACK to allow for HRTF tail-time - avoids glitch at end. 213 // FIXME: implement tailTime for each AudioNode for a more general solution to this problem. 214 // https://bugs.webkit.org/show_bug.cgi?id=77224 215 if (m_isGrain) 216 endFrame += 512; 217 218 // Do some sanity checking. 219 if (endFrame > bufferLength) 220 endFrame = bufferLength; 221 if (m_virtualReadIndex >= endFrame) 222 m_virtualReadIndex = 0; // reset to start 223 224 // If the .loop attribute is true, then values of m_loopStart == 0 && m_loopEnd == 0 implies 225 // that we should use the entire buffer as the loop, otherwise use the loop values in m_loopStart and m_loopEnd. 226 double virtualEndFrame = endFrame; 227 double virtualDeltaFrames = endFrame; 228 229 if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 && m_loopEnd > 0 && m_loopStart < m_loopEnd) { 230 // Convert from seconds to sample-frames. 231 double loopStartFrame = m_loopStart * buffer()->sampleRate(); 232 double loopEndFrame = m_loopEnd * buffer()->sampleRate(); 233 234 virtualEndFrame = min(loopEndFrame, virtualEndFrame); 235 virtualDeltaFrames = virtualEndFrame - loopStartFrame; 236 } 237 238 239 double pitchRate = totalPitchRate(); 240 241 // Sanity check that our playback rate isn't larger than the loop size. 242 if (pitchRate >= virtualDeltaFrames) 243 return false; 244 245 // Get local copy. 246 double virtualReadIndex = m_virtualReadIndex; 247 248 // Render loop - reading from the source buffer to the destination using linear interpolation. 249 int framesToProcess = numberOfFrames; 250 251 const float** sourceChannels = m_sourceChannels.get(); 252 float** destinationChannels = m_destinationChannels.get(); 253 254 // Optimize for the very common case of playing back with pitchRate == 1. 255 // We can avoid the linear interpolation. 256 if (pitchRate == 1 && virtualReadIndex == floor(virtualReadIndex) 257 && virtualDeltaFrames == floor(virtualDeltaFrames) 258 && virtualEndFrame == floor(virtualEndFrame)) { 259 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); 260 unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames); 261 endFrame = static_cast<unsigned>(virtualEndFrame); 262 while (framesToProcess > 0) { 263 int framesToEnd = endFrame - readIndex; 264 int framesThisTime = min(framesToProcess, framesToEnd); 265 framesThisTime = 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 >= endFrame) { 276 readIndex -= deltaFrames; 277 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess)) 278 break; 279 } 280 } 281 virtualReadIndex = readIndex; 282 } else { 283 while (framesToProcess--) { 284 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); 285 double interpolationFactor = virtualReadIndex - readIndex; 286 287 // For linear interpolation we need the next sample-frame too. 288 unsigned readIndex2 = readIndex + 1; 289 if (readIndex2 >= bufferLength) { 290 if (loop()) { 291 // Make sure to wrap around at the end of the buffer. 292 readIndex2 = static_cast<unsigned>(virtualReadIndex + 1 - virtualDeltaFrames); 293 } else 294 readIndex2 = readIndex; 295 } 296 297 // Final sanity check on buffer access. 298 // FIXME: as an optimization, try to get rid of this inner-loop check and put assertions and guards before the loop. 299 if (readIndex >= bufferLength || readIndex2 >= bufferLength) 300 break; 301 302 // Linear interpolation. 303 for (unsigned i = 0; i < numberOfChannels; ++i) { 304 float* destination = destinationChannels[i]; 305 const float* source = sourceChannels[i]; 306 307 double sample1 = source[readIndex]; 308 double sample2 = source[readIndex2]; 309 double sample = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2; 310 311 destination[writeIndex] = narrowPrecisionToFloat(sample); 312 } 313 writeIndex++; 314 315 virtualReadIndex += pitchRate; 316 317 // Wrap-around, retaining sub-sample position since virtualReadIndex is floating-point. 318 if (virtualReadIndex >= virtualEndFrame) { 319 virtualReadIndex -= virtualDeltaFrames; 320 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess)) 321 break; 322 } 323 } 324 } 325 326 bus->clearSilentFlag(); 327 328 m_virtualReadIndex = virtualReadIndex; 329 330 return true; 331 } 332 333 334 void AudioBufferSourceNode::reset() 335 { 336 m_virtualReadIndex = 0; 337 m_lastGain = gain()->value(); 338 } 339 340 void AudioBufferSourceNode::setBuffer(AudioBuffer* buffer, ExceptionState& exceptionState) 341 { 342 ASSERT(isMainThread()); 343 // FIXME: It does not look like we should throw if the buffer is null as 344 // the attribute is nullable in the specification. 345 if (!buffer) { 346 exceptionState.throwTypeError("buffer cannot be null"); 347 return; 348 } 349 350 // The context must be locked since changing the buffer can re-configure the number of channels that are output. 351 AudioContext::AutoLocker contextLocker(context()); 352 353 // This synchronizes with process(). 354 MutexLocker processLocker(m_processLock); 355 356 if (buffer) { 357 // Do any necesssary re-configuration to the buffer's number of channels. 358 unsigned numberOfChannels = buffer->numberOfChannels(); 359 360 if (numberOfChannels > AudioContext::maxNumberOfChannels()) { 361 exceptionState.throwTypeError("number of input channels (" + String::number(numberOfChannels) 362 + ") exceeds maximum (" 363 + String::number(AudioContext::maxNumberOfChannels()) + ")."); 364 return; 365 } 366 367 output(0)->setNumberOfChannels(numberOfChannels); 368 369 m_sourceChannels = adoptArrayPtr(new const float* [numberOfChannels]); 370 m_destinationChannels = adoptArrayPtr(new float* [numberOfChannels]); 371 372 for (unsigned i = 0; i < numberOfChannels; ++i) 373 m_sourceChannels[i] = buffer->getChannelData(i)->data(); 374 } 375 376 m_virtualReadIndex = 0; 377 m_buffer = buffer; 378 } 379 380 unsigned AudioBufferSourceNode::numberOfChannels() 381 { 382 return output(0)->numberOfChannels(); 383 } 384 385 void AudioBufferSourceNode::start(ExceptionState& exceptionState) 386 { 387 startPlaying(false, 0, 0, buffer() ? buffer()->duration() : 0, exceptionState); 388 } 389 390 void AudioBufferSourceNode::start(double when, ExceptionState& exceptionState) 391 { 392 startPlaying(false, when, 0, buffer() ? buffer()->duration() : 0, exceptionState); 393 } 394 395 void AudioBufferSourceNode::start(double when, double grainOffset, ExceptionState& exceptionState) 396 { 397 startPlaying(true, when, grainOffset, buffer() ? buffer()->duration() : 0, exceptionState); 398 } 399 400 void AudioBufferSourceNode::start(double when, double grainOffset, double grainDuration, ExceptionState& exceptionState) 401 { 402 startPlaying(true, when, grainOffset, grainDuration, exceptionState); 403 } 404 405 void AudioBufferSourceNode::startPlaying(bool isGrain, double when, double grainOffset, double grainDuration, ExceptionState& exceptionState) 406 { 407 ASSERT(isMainThread()); 408 409 if (m_playbackState != UNSCHEDULED_STATE) { 410 exceptionState.throwDOMException( 411 InvalidStateError, 412 "cannot call start more than once."); 413 return; 414 } 415 416 if (!buffer()) 417 return; 418 419 if (isGrain) { 420 // Do sanity checking of grain parameters versus buffer size. 421 double bufferDuration = buffer()->duration(); 422 423 grainOffset = max(0.0, grainOffset); 424 grainOffset = min(bufferDuration, grainOffset); 425 m_grainOffset = grainOffset; 426 427 double maxDuration = bufferDuration - grainOffset; 428 429 grainDuration = max(0.0, grainDuration); 430 grainDuration = min(maxDuration, grainDuration); 431 m_grainDuration = grainDuration; 432 } 433 434 m_isGrain = isGrain; 435 m_startTime = when; 436 437 // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation 438 // at a sub-sample position since it will degrade the quality. 439 // When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer. 440 // Since playbackRate == 1 is very common, it's worth considering quality. 441 m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer()->sampleRate()); 442 443 m_playbackState = SCHEDULED_STATE; 444 } 445 446 void AudioBufferSourceNode::noteGrainOn(double when, double grainOffset, double grainDuration, ExceptionState& exceptionState) 447 { 448 // Handle unspecified duration where 0 means the rest of the buffer. 449 if (!grainDuration && buffer()) 450 grainDuration = buffer()->duration(); 451 startPlaying(true, when, grainOffset, grainDuration, exceptionState); 452 } 453 454 double AudioBufferSourceNode::totalPitchRate() 455 { 456 double dopplerRate = 1.0; 457 if (m_pannerNode) 458 dopplerRate = m_pannerNode->dopplerRate(); 459 460 // Incorporate buffer's sample-rate versus AudioContext's sample-rate. 461 // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case. 462 double sampleRateFactor = 1.0; 463 if (buffer()) 464 sampleRateFactor = buffer()->sampleRate() / sampleRate(); 465 466 double basePitchRate = playbackRate()->value(); 467 468 double totalRate = dopplerRate * sampleRateFactor * basePitchRate; 469 470 // Sanity check the total rate. It's very important that the resampler not get any bad rate values. 471 totalRate = max(0.0, totalRate); 472 if (!totalRate) 473 totalRate = 1; // zero rate is considered illegal 474 totalRate = min(MaxRate, totalRate); 475 476 bool isTotalRateValid = !std::isnan(totalRate) && !std::isinf(totalRate); 477 ASSERT(isTotalRateValid); 478 if (!isTotalRateValid) 479 totalRate = 1.0; 480 481 return totalRate; 482 } 483 484 bool AudioBufferSourceNode::propagatesSilence() const 485 { 486 return !isPlayingOrScheduled() || hasFinished() || !m_buffer; 487 } 488 489 void AudioBufferSourceNode::setPannerNode(PannerNode* pannerNode) 490 { 491 if (m_pannerNode != pannerNode && !hasFinished()) { 492 if (pannerNode) 493 pannerNode->ref(AudioNode::RefTypeConnection); 494 if (m_pannerNode) 495 m_pannerNode->deref(AudioNode::RefTypeConnection); 496 497 m_pannerNode = pannerNode; 498 } 499 } 500 501 void AudioBufferSourceNode::clearPannerNode() 502 { 503 if (m_pannerNode) { 504 m_pannerNode->deref(AudioNode::RefTypeConnection); 505 m_pannerNode = 0; 506 } 507 } 508 509 void AudioBufferSourceNode::finish() 510 { 511 clearPannerNode(); 512 ASSERT(!m_pannerNode); 513 AudioScheduledSourceNode::finish(); 514 } 515 516 } // namespace WebCore 517 518 #endif // ENABLE(WEB_AUDIO) 519