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