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 <algorithm> 34 #include <wtf/MathExtras.h> 35 36 using namespace std; 37 38 namespace WebCore { 39 40 const double DefaultGrainDuration = 0.020; // 20ms 41 42 PassRefPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, double sampleRate) 43 { 44 return adoptRef(new AudioBufferSourceNode(context, sampleRate)); 45 } 46 47 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* context, double sampleRate) 48 : AudioSourceNode(context, sampleRate) 49 , m_buffer(0) 50 , m_isPlaying(false) 51 , m_isLooping(false) 52 , m_hasFinished(false) 53 , m_startTime(0.0) 54 , m_schedulingFrameDelay(0) 55 , m_readIndex(0) 56 , m_isGrain(false) 57 , m_grainOffset(0.0) 58 , m_grainDuration(DefaultGrainDuration) 59 , m_grainFrameCount(0) 60 , m_lastGain(1.0) 61 , m_pannerNode(0) 62 { 63 setType(NodeTypeAudioBufferSource); 64 65 m_gain = AudioGain::create("gain", 1.0, 0.0, 1.0); 66 m_playbackRate = AudioParam::create("playbackRate", 1.0, 0.0, AudioResampler::MaxRate); 67 68 // Default to mono. A call to setBuffer() will set the number of output channels to that of the buffer. 69 addOutput(adoptPtr(new AudioNodeOutput(this, 1))); 70 71 initialize(); 72 } 73 74 AudioBufferSourceNode::~AudioBufferSourceNode() 75 { 76 uninitialize(); 77 } 78 79 void AudioBufferSourceNode::process(size_t framesToProcess) 80 { 81 AudioBus* outputBus = output(0)->bus(); 82 83 if (!isInitialized()) { 84 outputBus->zero(); 85 return; 86 } 87 88 // The audio thread can't block on this lock, so we call tryLock() instead. 89 // Careful - this is a tryLock() and not an autolocker, so we must unlock() before every return. 90 if (m_processLock.tryLock()) { 91 // Check if it's time to start playing. 92 double sampleRate = this->sampleRate(); 93 double pitchRate = totalPitchRate(); 94 double quantumStartTime = context()->currentTime(); 95 double quantumEndTime = quantumStartTime + framesToProcess / sampleRate; 96 97 if (!m_isPlaying || m_hasFinished || !buffer() || m_startTime >= quantumEndTime) { 98 // FIXME: can optimize here by propagating silent hint instead of forcing the whole chain to process silence. 99 outputBus->zero(); 100 m_processLock.unlock(); 101 return; 102 } 103 104 // Handle sample-accurate scheduling so that buffer playback will happen at a very precise time. 105 m_schedulingFrameDelay = 0; 106 if (m_startTime >= quantumStartTime) { 107 // m_schedulingFrameDelay is set here only the very first render quantum (because of above check: m_startTime >= quantumEndTime) 108 // So: quantumStartTime <= m_startTime < quantumEndTime 109 ASSERT(m_startTime < quantumEndTime); 110 111 double startTimeInQuantum = m_startTime - quantumStartTime; 112 double startFrameInQuantum = startTimeInQuantum * sampleRate; 113 114 // m_schedulingFrameDelay is used in provideInput(), so factor in the current playback pitch rate. 115 m_schedulingFrameDelay = static_cast<int>(pitchRate * startFrameInQuantum); 116 } 117 118 // FIXME: optimization opportunity: 119 // With a bit of work, it should be possible to avoid going through the resampler completely when the pitchRate == 1, 120 // especially if the pitchRate has never deviated from 1 in the past. 121 122 // Read the samples through the pitch resampler. Our provideInput() method will be called by the resampler. 123 m_resampler.setRate(pitchRate); 124 m_resampler.process(this, outputBus, framesToProcess); 125 126 // Apply the gain (in-place) to the output bus. 127 double totalGain = gain()->value() * m_buffer->gain(); 128 outputBus->copyWithGainFrom(*outputBus, &m_lastGain, totalGain); 129 130 m_processLock.unlock(); 131 } else { 132 // Too bad - the tryLock() failed. We must be in the middle of changing buffers and were already outputting silence anyway. 133 outputBus->zero(); 134 } 135 } 136 137 // The resampler calls us back here to get the input samples from our buffer. 138 void AudioBufferSourceNode::provideInput(AudioBus* bus, size_t numberOfFrames) 139 { 140 ASSERT(context()->isAudioThread()); 141 142 // Basic sanity checking 143 ASSERT(bus); 144 ASSERT(buffer()); 145 if (!bus || !buffer()) 146 return; 147 148 unsigned numberOfChannels = this->numberOfChannels(); 149 unsigned busNumberOfChannels = bus->numberOfChannels(); 150 151 // FIXME: we can add support for sources with more than two channels, but this is not a common case. 152 bool channelCountGood = numberOfChannels == busNumberOfChannels && (numberOfChannels == 1 || numberOfChannels == 2); 153 ASSERT(channelCountGood); 154 if (!channelCountGood) 155 return; 156 157 // Get the destination pointers. 158 float* destinationL = bus->channel(0)->data(); 159 ASSERT(destinationL); 160 if (!destinationL) 161 return; 162 float* destinationR = (numberOfChannels < 2) ? 0 : bus->channel(1)->data(); 163 164 size_t bufferLength = buffer()->length(); 165 double bufferSampleRate = buffer()->sampleRate(); 166 167 // Calculate the start and end frames in our buffer that we want to play. 168 // If m_isGrain is true, then we will be playing a portion of the total buffer. 169 unsigned startFrame = m_isGrain ? static_cast<unsigned>(m_grainOffset * bufferSampleRate) : 0; 170 unsigned endFrame = m_isGrain ? static_cast<unsigned>(startFrame + m_grainDuration * bufferSampleRate) : bufferLength; 171 172 // This is a HACK to allow for HRTF tail-time - avoids glitch at end. 173 // FIXME: implement tailTime for each AudioNode for a more general solution to this problem. 174 if (m_isGrain) 175 endFrame += 512; 176 177 // Do some sanity checking. 178 if (startFrame >= bufferLength) 179 startFrame = !bufferLength ? 0 : bufferLength - 1; 180 if (endFrame > bufferLength) 181 endFrame = bufferLength; 182 if (m_readIndex >= endFrame) 183 m_readIndex = startFrame; // reset to start 184 185 int framesToProcess = numberOfFrames; 186 187 // Handle sample-accurate scheduling so that we play the buffer at a very precise time. 188 // m_schedulingFrameDelay will only be non-zero the very first time that provideInput() is called, which corresponds 189 // with the very start of the buffer playback. 190 if (m_schedulingFrameDelay > 0) { 191 ASSERT(m_schedulingFrameDelay <= framesToProcess); 192 if (m_schedulingFrameDelay <= framesToProcess) { 193 // Generate silence for the initial portion of the destination. 194 memset(destinationL, 0, sizeof(float) * m_schedulingFrameDelay); 195 destinationL += m_schedulingFrameDelay; 196 if (destinationR) { 197 memset(destinationR, 0, sizeof(float) * m_schedulingFrameDelay); 198 destinationR += m_schedulingFrameDelay; 199 } 200 201 // Since we just generated silence for the initial portion, we have fewer frames to provide. 202 framesToProcess -= m_schedulingFrameDelay; 203 } 204 } 205 206 // We have to generate a certain number of output sample-frames, but we need to handle the case where we wrap around 207 // from the end of the buffer to the start if playing back with looping and also the case where we simply reach the 208 // end of the sample data, but haven't yet rendered numberOfFrames worth of output. 209 while (framesToProcess > 0) { 210 ASSERT(m_readIndex <= endFrame); 211 if (m_readIndex > endFrame) 212 return; 213 214 // Figure out how many frames we can process this time. 215 int framesAvailable = endFrame - m_readIndex; 216 int framesThisTime = min(framesToProcess, framesAvailable); 217 218 // Create the destination bus for the part of the destination we're processing this time. 219 AudioBus currentDestinationBus(busNumberOfChannels, framesThisTime, false); 220 currentDestinationBus.setChannelMemory(0, destinationL, framesThisTime); 221 if (busNumberOfChannels > 1) 222 currentDestinationBus.setChannelMemory(1, destinationR, framesThisTime); 223 224 // Generate output from the buffer. 225 readFromBuffer(¤tDestinationBus, framesThisTime); 226 227 // Update the destination pointers. 228 destinationL += framesThisTime; 229 if (busNumberOfChannels > 1) 230 destinationR += framesThisTime; 231 232 framesToProcess -= framesThisTime; 233 234 // Handle the case where we reach the end of the part of the sample data we're supposed to play for the buffer. 235 if (m_readIndex >= endFrame) { 236 m_readIndex = startFrame; 237 m_grainFrameCount = 0; 238 239 if (!looping()) { 240 // If we're not looping, then stop playing when we get to the end. 241 m_isPlaying = false; 242 243 if (framesToProcess > 0) { 244 // We're not looping and we've reached the end of the sample data, but we still need to provide more output, 245 // so generate silence for the remaining. 246 memset(destinationL, 0, sizeof(float) * framesToProcess); 247 248 if (destinationR) 249 memset(destinationR, 0, sizeof(float) * framesToProcess); 250 } 251 252 if (!m_hasFinished) { 253 // Let the context dereference this AudioNode. 254 context()->notifyNodeFinishedProcessing(this); 255 m_hasFinished = true; 256 } 257 return; 258 } 259 } 260 } 261 } 262 263 void AudioBufferSourceNode::readFromBuffer(AudioBus* destinationBus, size_t framesToProcess) 264 { 265 bool isBusGood = destinationBus && destinationBus->length() == framesToProcess && destinationBus->numberOfChannels() == numberOfChannels(); 266 ASSERT(isBusGood); 267 if (!isBusGood) 268 return; 269 270 unsigned numberOfChannels = this->numberOfChannels(); 271 // FIXME: we can add support for sources with more than two channels, but this is not a common case. 272 bool channelCountGood = numberOfChannels == 1 || numberOfChannels == 2; 273 ASSERT(channelCountGood); 274 if (!channelCountGood) 275 return; 276 277 // Get pointers to the start of the sample buffer. 278 float* sourceL = m_buffer->getChannelData(0)->data(); 279 float* sourceR = m_buffer->numberOfChannels() == 2 ? m_buffer->getChannelData(1)->data() : 0; 280 281 // Sanity check buffer access. 282 bool isSourceGood = sourceL && (numberOfChannels == 1 || sourceR) && m_readIndex + framesToProcess <= m_buffer->length(); 283 ASSERT(isSourceGood); 284 if (!isSourceGood) 285 return; 286 287 // Offset the pointers to the current read position in the sample buffer. 288 sourceL += m_readIndex; 289 sourceR += m_readIndex; 290 291 // Get pointers to the destination. 292 float* destinationL = destinationBus->channel(0)->data(); 293 float* destinationR = numberOfChannels == 2 ? destinationBus->channel(1)->data() : 0; 294 bool isDestinationGood = destinationL && (numberOfChannels == 1 || destinationR); 295 ASSERT(isDestinationGood); 296 if (!isDestinationGood) 297 return; 298 299 if (m_isGrain) 300 readFromBufferWithGrainEnvelope(sourceL, sourceR, destinationL, destinationR, framesToProcess); 301 else { 302 // Simply copy the data from the source buffer to the destination. 303 memcpy(destinationL, sourceL, sizeof(float) * framesToProcess); 304 if (numberOfChannels == 2) 305 memcpy(destinationR, sourceR, sizeof(float) * framesToProcess); 306 } 307 308 // Advance the buffer's read index. 309 m_readIndex += framesToProcess; 310 } 311 312 void AudioBufferSourceNode::readFromBufferWithGrainEnvelope(float* sourceL, float* sourceR, float* destinationL, float* destinationR, size_t framesToProcess) 313 { 314 ASSERT(sourceL && destinationL); 315 if (!sourceL || !destinationL) 316 return; 317 318 int grainFrameLength = static_cast<int>(m_grainDuration * m_buffer->sampleRate()); 319 bool isStereo = sourceR && destinationR; 320 321 int n = framesToProcess; 322 while (n--) { 323 // Apply the grain envelope. 324 float x = static_cast<float>(m_grainFrameCount) / static_cast<float>(grainFrameLength); 325 m_grainFrameCount++; 326 327 x = min(1.0f, x); 328 float grainEnvelope = sinf(piFloat * x); 329 330 *destinationL++ = grainEnvelope * *sourceL++; 331 332 if (isStereo) 333 *destinationR++ = grainEnvelope * *sourceR++; 334 } 335 } 336 337 void AudioBufferSourceNode::reset() 338 { 339 m_resampler.reset(); 340 m_readIndex = 0; 341 m_grainFrameCount = 0; 342 m_lastGain = gain()->value(); 343 } 344 345 void AudioBufferSourceNode::setBuffer(AudioBuffer* buffer) 346 { 347 ASSERT(isMainThread()); 348 349 // The context must be locked since changing the buffer can re-configure the number of channels that are output. 350 AudioContext::AutoLocker contextLocker(context()); 351 352 // This synchronizes with process(). 353 MutexLocker processLocker(m_processLock); 354 355 if (buffer) { 356 // Do any necesssary re-configuration to the buffer's number of channels. 357 unsigned numberOfChannels = buffer->numberOfChannels(); 358 m_resampler.configureChannels(numberOfChannels); 359 output(0)->setNumberOfChannels(numberOfChannels); 360 } 361 362 m_readIndex = 0; 363 m_buffer = buffer; 364 } 365 366 unsigned AudioBufferSourceNode::numberOfChannels() 367 { 368 return output(0)->numberOfChannels(); 369 } 370 371 void AudioBufferSourceNode::noteOn(double when) 372 { 373 ASSERT(isMainThread()); 374 if (m_isPlaying) 375 return; 376 377 m_isGrain = false; 378 m_startTime = when; 379 m_readIndex = 0; 380 m_isPlaying = true; 381 } 382 383 void AudioBufferSourceNode::noteGrainOn(double when, double grainOffset, double grainDuration) 384 { 385 ASSERT(isMainThread()); 386 if (m_isPlaying) 387 return; 388 389 if (!buffer()) 390 return; 391 392 // Do sanity checking of grain parameters versus buffer size. 393 double bufferDuration = buffer()->duration(); 394 395 if (grainDuration > bufferDuration) 396 return; // FIXME: maybe should throw exception - consider in specification. 397 398 double maxGrainOffset = bufferDuration - grainDuration; 399 maxGrainOffset = max(0.0, maxGrainOffset); 400 401 grainOffset = max(0.0, grainOffset); 402 grainOffset = min(maxGrainOffset, grainOffset); 403 m_grainOffset = grainOffset; 404 405 m_grainDuration = grainDuration; 406 m_grainFrameCount = 0; 407 408 m_isGrain = true; 409 m_startTime = when; 410 m_readIndex = static_cast<int>(m_grainOffset * buffer()->sampleRate()); 411 m_isPlaying = true; 412 } 413 414 void AudioBufferSourceNode::noteOff(double) 415 { 416 ASSERT(isMainThread()); 417 if (!m_isPlaying) 418 return; 419 420 // FIXME: the "when" argument to this method is ignored. 421 m_isPlaying = false; 422 m_readIndex = 0; 423 } 424 425 double AudioBufferSourceNode::totalPitchRate() 426 { 427 double dopplerRate = 1.0; 428 if (m_pannerNode.get()) 429 dopplerRate = m_pannerNode->dopplerRate(); 430 431 // Incorporate buffer's sample-rate versus AudioContext's sample-rate. 432 // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case. 433 double sampleRateFactor = 1.0; 434 if (buffer()) 435 sampleRateFactor = buffer()->sampleRate() / sampleRate(); 436 437 double basePitchRate = playbackRate()->value(); 438 439 double totalRate = dopplerRate * sampleRateFactor * basePitchRate; 440 441 // Sanity check the total rate. It's very important that the resampler not get any bad rate values. 442 totalRate = max(0.0, totalRate); 443 totalRate = min(AudioResampler::MaxRate, totalRate); 444 445 bool isTotalRateValid = !isnan(totalRate) && !isinf(totalRate); 446 ASSERT(isTotalRateValid); 447 if (!isTotalRateValid) 448 totalRate = 1.0; 449 450 return totalRate; 451 } 452 453 } // namespace WebCore 454 455 #endif // ENABLE(WEB_AUDIO) 456