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 "core/page/PageConsole.h" 32 #include "core/platform/FloatConversion.h" 33 #include "core/platform/audio/AudioUtilities.h" 34 #include "modules/webaudio/AudioContext.h" 35 #include "modules/webaudio/AudioNodeOutput.h" 36 #include <algorithm> 37 #include "wtf/MainThread.h" 38 #include "wtf/MathExtras.h" 39 40 using namespace std; 41 42 namespace WebCore { 43 44 const double DefaultGrainDuration = 0.020; // 20ms 45 46 // Arbitrary upper limit on playback rate. 47 // Higher than expected rates can be useful when playing back oversampled buffers 48 // to minimize linear interpolation aliasing. 49 const double MaxRate = 1024; 50 51 PassRefPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, float sampleRate) 52 { 53 return adoptRef(new AudioBufferSourceNode(context, sampleRate)); 54 } 55 56 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* context, float sampleRate) 57 : AudioScheduledSourceNode(context, sampleRate) 58 , m_buffer(0) 59 , m_isLooping(false) 60 , m_loopStart(0) 61 , m_loopEnd(0) 62 , m_virtualReadIndex(0) 63 , m_isGrain(false) 64 , m_grainOffset(0.0) 65 , m_grainDuration(DefaultGrainDuration) 66 , m_lastGain(1.0) 67 , m_pannerNode(0) 68 { 69 ScriptWrappable::init(this); 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, 0.0, MaxRate); 74 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))); 77 78 initialize(); 79 } 80 81 AudioBufferSourceNode::~AudioBufferSourceNode() 82 { 83 clearPannerNode(); 84 uninitialize(); 85 } 86 87 void AudioBufferSourceNode::process(size_t framesToProcess) 88 { 89 AudioBus* 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 call tryLock() instead. 97 MutexTryLocker tryLocker(m_processLock); 98 if (tryLocker.locked()) { 99 if (!buffer()) { 100 outputBus->zero(); 101 return; 102 } 103 104 // After calling setBuffer() with a buffer having a different number of channels, there can in rare cases be a slight delay 105 // before the output bus is updated to the new number of channels because of use of tryLocks() in the context's updating system. 106 // In this case, if the the buffer has just been changed and we're not quite ready yet, then just output silence. 107 if (numberOfChannels() != buffer()->numberOfChannels()) { 108 outputBus->zero(); 109 return; 110 } 111 112 size_t quantumFrameOffset; 113 size_t bufferFramesToProcess; 114 115 updateSchedulingInfo(framesToProcess, 116 outputBus, 117 quantumFrameOffset, 118 bufferFramesToProcess); 119 120 if (!bufferFramesToProcess) { 121 outputBus->zero(); 122 return; 123 } 124 125 for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i) 126 m_destinationChannels[i] = outputBus->channel(i)->mutableData(); 127 128 // Render by reading directly from the buffer. 129 if (!renderFromBuffer(outputBus, quantumFrameOffset, bufferFramesToProcess)) { 130 outputBus->zero(); 131 return; 132 } 133 134 // Apply the gain (in-place) to the output bus. 135 float totalGain = gain()->value() * m_buffer->gain(); 136 outputBus->copyWithGainFrom(*outputBus, &m_lastGain, totalGain); 137 outputBus->clearSilentFlag(); 138 } else { 139 // Too bad - the tryLock() failed. We must be in the middle of changing buffers and were already outputting silence anyway. 140 outputBus->zero(); 141 } 142 } 143 144 // Returns true if we're finished. 145 bool AudioBufferSourceNode::renderSilenceAndFinishIfNotLooping(AudioBus*, unsigned index, size_t framesToProcess) 146 { 147 if (!loop()) { 148 // If we're not looping, then stop playing when we get to the end. 149 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); 155 } 156 157 finish(); 158 return true; 159 } 160 return false; 161 } 162 163 bool AudioBufferSourceNode::renderFromBuffer(AudioBus* bus, unsigned destinationFrameOffset, size_t numberOfFrames) 164 { 165 ASSERT(context()->isAudioThread()); 166 167 // Basic sanity checking 168 ASSERT(bus); 169 ASSERT(buffer()); 170 if (!bus || !buffer()) 171 return false; 172 173 unsigned numberOfChannels = this->numberOfChannels(); 174 unsigned busNumberOfChannels = bus->numberOfChannels(); 175 176 bool channelCountGood = numberOfChannels && numberOfChannels == busNumberOfChannels; 177 ASSERT(channelCountGood); 178 if (!channelCountGood) 179 return false; 180 181 // Sanity check destinationFrameOffset, numberOfFrames. 182 size_t destinationLength = bus->length(); 183 184 bool isLengthGood = destinationLength <= 4096 && numberOfFrames <= 4096; 185 ASSERT(isLengthGood); 186 if (!isLengthGood) 187 return false; 188 189 bool isOffsetGood = destinationFrameOffset <= destinationLength && destinationFrameOffset + numberOfFrames <= destinationLength; 190 ASSERT(isOffsetGood); 191 if (!isOffsetGood) 192 return false; 193 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); 198 } 199 200 // Offset the pointers to the correct offset frame. 201 unsigned writeIndex = destinationFrameOffset; 202 203 size_t bufferLength = buffer()->length(); 204 double bufferSampleRate = buffer()->sampleRate(); 205 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; 209 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 213 if (m_isGrain) 214 endFrame += 512; 215 216 // Do some sanity checking. 217 if (endFrame > bufferLength) 218 endFrame = bufferLength; 219 if (m_virtualReadIndex >= endFrame) 220 m_virtualReadIndex = 0; // reset to start 221 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; 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 loopStartFrame = m_loopStart * buffer()->sampleRate(); 230 double loopEndFrame = m_loopEnd * buffer()->sampleRate(); 231 232 virtualEndFrame = min(loopEndFrame, virtualEndFrame); 233 virtualDeltaFrames = virtualEndFrame - loopStartFrame; 234 } 235 236 237 double pitchRate = totalPitchRate(); 238 239 // Sanity check that our playback rate isn't larger than the loop size. 240 if (pitchRate >= virtualDeltaFrames) 241 return false; 242 243 // Get local copy. 244 double virtualReadIndex = m_virtualReadIndex; 245 246 // Render loop - reading from the source buffer to the destination using linear interpolation. 247 int framesToProcess = numberOfFrames; 248 249 const float** sourceChannels = m_sourceChannels.get(); 250 float** destinationChannels = m_destinationChannels.get(); 251 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 = min(framesToProcess, framesToEnd); 263 framesThisTime = max(0, framesThisTime); 264 265 for (unsigned i = 0; i < numberOfChannels; ++i) 266 memcpy(destinationChannels[i] + writeIndex, sourceChannels[i] + readIndex, sizeof(float) * framesThisTime); 267 268 writeIndex += framesThisTime; 269 readIndex += framesThisTime; 270 framesToProcess -= framesThisTime; 271 272 // Wrap-around. 273 if (readIndex >= endFrame) { 274 readIndex -= deltaFrames; 275 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess)) 276 break; 277 } 278 } 279 virtualReadIndex = readIndex; 280 } else { 281 while (framesToProcess--) { 282 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); 283 double interpolationFactor = virtualReadIndex - readIndex; 284 285 // For linear interpolation we need the next sample-frame too. 286 unsigned readIndex2 = readIndex + 1; 287 if (readIndex2 >= bufferLength) { 288 if (loop()) { 289 // Make sure to wrap around at the end of the buffer. 290 readIndex2 = static_cast<unsigned>(virtualReadIndex + 1 - virtualDeltaFrames); 291 } else 292 readIndex2 = readIndex; 293 } 294 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) 298 break; 299 300 // Linear interpolation. 301 for (unsigned i = 0; i < numberOfChannels; ++i) { 302 float* destination = destinationChannels[i]; 303 const float* source = sourceChannels[i]; 304 305 double sample1 = source[readIndex]; 306 double sample2 = source[readIndex2]; 307 double sample = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2; 308 309 destination[writeIndex] = narrowPrecisionToFloat(sample); 310 } 311 writeIndex++; 312 313 virtualReadIndex += pitchRate; 314 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)) 319 break; 320 } 321 } 322 } 323 324 bus->clearSilentFlag(); 325 326 m_virtualReadIndex = virtualReadIndex; 327 328 return true; 329 } 330 331 332 void AudioBufferSourceNode::reset() 333 { 334 m_virtualReadIndex = 0; 335 m_lastGain = gain()->value(); 336 } 337 338 bool AudioBufferSourceNode::setBuffer(AudioBuffer* buffer) 339 { 340 ASSERT(isMainThread()); 341 342 // The context must be locked since changing the buffer can re-configure the number of channels that are output. 343 AudioContext::AutoLocker contextLocker(context()); 344 345 // This synchronizes with process(). 346 MutexLocker processLocker(m_processLock); 347 348 if (buffer) { 349 // Do any necesssary re-configuration to the buffer's number of channels. 350 unsigned numberOfChannels = buffer->numberOfChannels(); 351 352 if (numberOfChannels > AudioContext::maxNumberOfChannels()) 353 return false; 354 355 output(0)->setNumberOfChannels(numberOfChannels); 356 357 m_sourceChannels = adoptArrayPtr(new const float* [numberOfChannels]); 358 m_destinationChannels = adoptArrayPtr(new float* [numberOfChannels]); 359 360 for (unsigned i = 0; i < numberOfChannels; ++i) 361 m_sourceChannels[i] = buffer->getChannelData(i)->data(); 362 } 363 364 m_virtualReadIndex = 0; 365 m_buffer = buffer; 366 367 return true; 368 } 369 370 unsigned AudioBufferSourceNode::numberOfChannels() 371 { 372 return output(0)->numberOfChannels(); 373 } 374 375 void AudioBufferSourceNode::startGrain(double when, double grainOffset) 376 { 377 // Duration of 0 has special value, meaning calculate based on the entire buffer's duration. 378 startGrain(when, grainOffset, 0); 379 } 380 381 void AudioBufferSourceNode::startGrain(double when, double grainOffset, double grainDuration) 382 { 383 ASSERT(isMainThread()); 384 385 if (m_playbackState != UNSCHEDULED_STATE) 386 return; 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 // Handle default/unspecified duration. 399 double maxDuration = bufferDuration - grainOffset; 400 if (!grainDuration) 401 grainDuration = maxDuration; 402 403 grainDuration = max(0.0, grainDuration); 404 grainDuration = min(maxDuration, grainDuration); 405 m_grainDuration = grainDuration; 406 407 m_isGrain = true; 408 m_startTime = when; 409 410 // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation 411 // at a sub-sample position since it will degrade the quality. 412 // When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer. 413 // Since playbackRate == 1 is very common, it's worth considering quality. 414 m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer()->sampleRate()); 415 416 m_playbackState = SCHEDULED_STATE; 417 } 418 419 void AudioBufferSourceNode::noteGrainOn(double when, double grainOffset, double grainDuration) 420 { 421 startGrain(when, grainOffset, grainDuration); 422 } 423 424 double AudioBufferSourceNode::totalPitchRate() 425 { 426 double dopplerRate = 1.0; 427 if (m_pannerNode) 428 dopplerRate = m_pannerNode->dopplerRate(); 429 430 // Incorporate buffer's sample-rate versus AudioContext's sample-rate. 431 // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case. 432 double sampleRateFactor = 1.0; 433 if (buffer()) 434 sampleRateFactor = buffer()->sampleRate() / sampleRate(); 435 436 double basePitchRate = playbackRate()->value(); 437 438 double totalRate = dopplerRate * sampleRateFactor * basePitchRate; 439 440 // Sanity check the total rate. It's very important that the resampler not get any bad rate values. 441 totalRate = max(0.0, totalRate); 442 if (!totalRate) 443 totalRate = 1; // zero rate is considered illegal 444 totalRate = min(MaxRate, totalRate); 445 446 bool isTotalRateValid = !std::isnan(totalRate) && !std::isinf(totalRate); 447 ASSERT(isTotalRateValid); 448 if (!isTotalRateValid) 449 totalRate = 1.0; 450 451 return totalRate; 452 } 453 454 bool AudioBufferSourceNode::propagatesSilence() const 455 { 456 return !isPlayingOrScheduled() || hasFinished() || !m_buffer; 457 } 458 459 void AudioBufferSourceNode::setPannerNode(PannerNode* pannerNode) 460 { 461 if (m_pannerNode != pannerNode && !hasFinished()) { 462 if (pannerNode) 463 pannerNode->ref(AudioNode::RefTypeConnection); 464 if (m_pannerNode) 465 m_pannerNode->deref(AudioNode::RefTypeConnection); 466 467 m_pannerNode = pannerNode; 468 } 469 } 470 471 void AudioBufferSourceNode::clearPannerNode() 472 { 473 if (m_pannerNode) { 474 m_pannerNode->deref(AudioNode::RefTypeConnection); 475 m_pannerNode = 0; 476 } 477 } 478 479 void AudioBufferSourceNode::finish() 480 { 481 clearPannerNode(); 482 ASSERT(!m_pannerNode); 483 AudioScheduledSourceNode::finish(); 484 } 485 486 } // namespace WebCore 487 488 #endif // ENABLE(WEB_AUDIO) 489