| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 #include "bindings/v8/ExceptionState.h" | 31 #include "bindings/v8/ExceptionState.h" |
| 32 #include "core/dom/ExceptionCode.h" | 32 #include "core/dom/ExceptionCode.h" |
| 33 #include "platform/audio/AudioUtilities.h" | 33 #include "platform/audio/AudioUtilities.h" |
| 34 #include "modules/webaudio/AudioContext.h" | 34 #include "modules/webaudio/AudioContext.h" |
| 35 #include "modules/webaudio/AudioNodeOutput.h" | 35 #include "modules/webaudio/AudioNodeOutput.h" |
| 36 #include "platform/FloatConversion.h" | 36 #include "platform/FloatConversion.h" |
| 37 #include "wtf/MainThread.h" | 37 #include "wtf/MainThread.h" |
| 38 #include "wtf/MathExtras.h" | 38 #include "wtf/MathExtras.h" |
| 39 #include <algorithm> | 39 #include <algorithm> |
| 40 | 40 |
| 41 using namespace std; | |
| 42 | |
| 43 namespace WebCore { | 41 namespace WebCore { |
| 44 | 42 |
| 45 const double DefaultGrainDuration = 0.020; // 20ms | 43 const double DefaultGrainDuration = 0.020; // 20ms |
| 46 | 44 |
| 47 // Arbitrary upper limit on playback rate. | 45 // Arbitrary upper limit on playback rate. |
| 48 // Higher than expected rates can be useful when playing back oversampled buffer
s | 46 // Higher than expected rates can be useful when playing back oversampled buffer
s |
| 49 // to minimize linear interpolation aliasing. | 47 // to minimize linear interpolation aliasing. |
| 50 const double MaxRate = 1024; | 48 const double MaxRate = 1024; |
| 51 | 49 |
| 52 PassRefPtrWillBeRawPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(Audi
oContext* context, float sampleRate) | 50 PassRefPtrWillBeRawPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(Audi
oContext* context, float sampleRate) |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 // If the .loop attribute is true, then values of m_loopStart == 0 && m_loop
End == 0 implies | 217 // If the .loop attribute is true, then values of m_loopStart == 0 && m_loop
End == 0 implies |
| 220 // that we should use the entire buffer as the loop, otherwise use the loop
values in m_loopStart and m_loopEnd. | 218 // that we should use the entire buffer as the loop, otherwise use the loop
values in m_loopStart and m_loopEnd. |
| 221 double virtualEndFrame = endFrame; | 219 double virtualEndFrame = endFrame; |
| 222 double virtualDeltaFrames = endFrame; | 220 double virtualDeltaFrames = endFrame; |
| 223 | 221 |
| 224 if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 && m_loopEnd >
0 && m_loopStart < m_loopEnd) { | 222 if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 && m_loopEnd >
0 && m_loopStart < m_loopEnd) { |
| 225 // Convert from seconds to sample-frames. | 223 // Convert from seconds to sample-frames. |
| 226 double loopStartFrame = m_loopStart * buffer()->sampleRate(); | 224 double loopStartFrame = m_loopStart * buffer()->sampleRate(); |
| 227 double loopEndFrame = m_loopEnd * buffer()->sampleRate(); | 225 double loopEndFrame = m_loopEnd * buffer()->sampleRate(); |
| 228 | 226 |
| 229 virtualEndFrame = min(loopEndFrame, virtualEndFrame); | 227 virtualEndFrame = std::min(loopEndFrame, virtualEndFrame); |
| 230 virtualDeltaFrames = virtualEndFrame - loopStartFrame; | 228 virtualDeltaFrames = virtualEndFrame - loopStartFrame; |
| 231 } | 229 } |
| 232 | 230 |
| 233 | 231 |
| 234 double pitchRate = totalPitchRate(); | 232 double pitchRate = totalPitchRate(); |
| 235 | 233 |
| 236 // Sanity check that our playback rate isn't larger than the loop size. | 234 // Sanity check that our playback rate isn't larger than the loop size. |
| 237 if (pitchRate >= virtualDeltaFrames) | 235 if (pitchRate >= virtualDeltaFrames) |
| 238 return false; | 236 return false; |
| 239 | 237 |
| 240 // Get local copy. | 238 // Get local copy. |
| 241 double virtualReadIndex = m_virtualReadIndex; | 239 double virtualReadIndex = m_virtualReadIndex; |
| 242 | 240 |
| 243 // Render loop - reading from the source buffer to the destination using lin
ear interpolation. | 241 // Render loop - reading from the source buffer to the destination using lin
ear interpolation. |
| 244 int framesToProcess = numberOfFrames; | 242 int framesToProcess = numberOfFrames; |
| 245 | 243 |
| 246 const float** sourceChannels = m_sourceChannels.get(); | 244 const float** sourceChannels = m_sourceChannels.get(); |
| 247 float** destinationChannels = m_destinationChannels.get(); | 245 float** destinationChannels = m_destinationChannels.get(); |
| 248 | 246 |
| 249 // Optimize for the very common case of playing back with pitchRate == 1. | 247 // Optimize for the very common case of playing back with pitchRate == 1. |
| 250 // We can avoid the linear interpolation. | 248 // We can avoid the linear interpolation. |
| 251 if (pitchRate == 1 && virtualReadIndex == floor(virtualReadIndex) | 249 if (pitchRate == 1 && virtualReadIndex == floor(virtualReadIndex) |
| 252 && virtualDeltaFrames == floor(virtualDeltaFrames) | 250 && virtualDeltaFrames == floor(virtualDeltaFrames) |
| 253 && virtualEndFrame == floor(virtualEndFrame)) { | 251 && virtualEndFrame == floor(virtualEndFrame)) { |
| 254 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); | 252 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); |
| 255 unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames); | 253 unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames); |
| 256 endFrame = static_cast<unsigned>(virtualEndFrame); | 254 endFrame = static_cast<unsigned>(virtualEndFrame); |
| 257 while (framesToProcess > 0) { | 255 while (framesToProcess > 0) { |
| 258 int framesToEnd = endFrame - readIndex; | 256 int framesToEnd = endFrame - readIndex; |
| 259 int framesThisTime = min(framesToProcess, framesToEnd); | 257 int framesThisTime = std::min(framesToProcess, framesToEnd); |
| 260 framesThisTime = max(0, framesThisTime); | 258 framesThisTime = std::max(0, framesThisTime); |
| 261 | 259 |
| 262 for (unsigned i = 0; i < numberOfChannels; ++i) | 260 for (unsigned i = 0; i < numberOfChannels; ++i) |
| 263 memcpy(destinationChannels[i] + writeIndex, sourceChannels[i] +
readIndex, sizeof(float) * framesThisTime); | 261 memcpy(destinationChannels[i] + writeIndex, sourceChannels[i] +
readIndex, sizeof(float) * framesThisTime); |
| 264 | 262 |
| 265 writeIndex += framesThisTime; | 263 writeIndex += framesThisTime; |
| 266 readIndex += framesThisTime; | 264 readIndex += framesThisTime; |
| 267 framesToProcess -= framesThisTime; | 265 framesToProcess -= framesThisTime; |
| 268 | 266 |
| 269 // Wrap-around. | 267 // Wrap-around. |
| 270 if (readIndex >= endFrame) { | 268 if (readIndex >= endFrame) { |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 "cannot call start more than once."); | 383 "cannot call start more than once."); |
| 386 return; | 384 return; |
| 387 } | 385 } |
| 388 | 386 |
| 389 if (!buffer()) | 387 if (!buffer()) |
| 390 return; | 388 return; |
| 391 | 389 |
| 392 // Do sanity checking of grain parameters versus buffer size. | 390 // Do sanity checking of grain parameters versus buffer size. |
| 393 double bufferDuration = buffer()->duration(); | 391 double bufferDuration = buffer()->duration(); |
| 394 | 392 |
| 395 grainOffset = max(0.0, grainOffset); | 393 grainOffset = std::max(0.0, grainOffset); |
| 396 grainOffset = min(bufferDuration, grainOffset); | 394 grainOffset = std::min(bufferDuration, grainOffset); |
| 397 m_grainOffset = grainOffset; | 395 m_grainOffset = grainOffset; |
| 398 | 396 |
| 399 double maxDuration = bufferDuration - grainOffset; | 397 double maxDuration = bufferDuration - grainOffset; |
| 400 | 398 |
| 401 grainDuration = max(0.0, grainDuration); | 399 grainDuration = std::max(0.0, grainDuration); |
| 402 grainDuration = min(maxDuration, grainDuration); | 400 grainDuration = std::min(maxDuration, grainDuration); |
| 403 m_grainDuration = grainDuration; | 401 m_grainDuration = grainDuration; |
| 404 | 402 |
| 405 m_isGrain = true; | 403 m_isGrain = true; |
| 406 m_startTime = when; | 404 m_startTime = when; |
| 407 | 405 |
| 408 // We call timeToSampleFrame here since at playbackRate == 1 we don't want t
o go through linear interpolation | 406 // We call timeToSampleFrame here since at playbackRate == 1 we don't want t
o go through linear interpolation |
| 409 // at a sub-sample position since it will degrade the quality. | 407 // at a sub-sample position since it will degrade the quality. |
| 410 // When aligned to the sample-frame the playback will be identical to the PC
M data stored in the buffer. | 408 // When aligned to the sample-frame the playback will be identical to the PC
M data stored in the buffer. |
| 411 // Since playbackRate == 1 is very common, it's worth considering quality. | 409 // Since playbackRate == 1 is very common, it's worth considering quality. |
| 412 m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer
()->sampleRate()); | 410 m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer
()->sampleRate()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 424 // Normally it's not an issue because buffers are loaded at the AudioContext
's sample-rate, but we can handle it in any case. | 422 // Normally it's not an issue because buffers are loaded at the AudioContext
's sample-rate, but we can handle it in any case. |
| 425 double sampleRateFactor = 1.0; | 423 double sampleRateFactor = 1.0; |
| 426 if (buffer()) | 424 if (buffer()) |
| 427 sampleRateFactor = buffer()->sampleRate() / sampleRate(); | 425 sampleRateFactor = buffer()->sampleRate() / sampleRate(); |
| 428 | 426 |
| 429 double basePitchRate = playbackRate()->value(); | 427 double basePitchRate = playbackRate()->value(); |
| 430 | 428 |
| 431 double totalRate = dopplerRate * sampleRateFactor * basePitchRate; | 429 double totalRate = dopplerRate * sampleRateFactor * basePitchRate; |
| 432 | 430 |
| 433 // Sanity check the total rate. It's very important that the resampler not
get any bad rate values. | 431 // Sanity check the total rate. It's very important that the resampler not
get any bad rate values. |
| 434 totalRate = max(0.0, totalRate); | 432 totalRate = std::max(0.0, totalRate); |
| 435 if (!totalRate) | 433 if (!totalRate) |
| 436 totalRate = 1; // zero rate is considered illegal | 434 totalRate = 1; // zero rate is considered illegal |
| 437 totalRate = min(MaxRate, totalRate); | 435 totalRate = std::min(MaxRate, totalRate); |
| 438 | 436 |
| 439 bool isTotalRateValid = !std::isnan(totalRate) && !std::isinf(totalRate); | 437 bool isTotalRateValid = !std::isnan(totalRate) && !std::isinf(totalRate); |
| 440 ASSERT(isTotalRateValid); | 438 ASSERT(isTotalRateValid); |
| 441 if (!isTotalRateValid) | 439 if (!isTotalRateValid) |
| 442 totalRate = 1.0; | 440 totalRate = 1.0; |
| 443 | 441 |
| 444 return totalRate; | 442 return totalRate; |
| 445 } | 443 } |
| 446 | 444 |
| 447 bool AudioBufferSourceNode::propagatesSilence() const | 445 bool AudioBufferSourceNode::propagatesSilence() const |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 void AudioBufferSourceNode::trace(Visitor* visitor) | 477 void AudioBufferSourceNode::trace(Visitor* visitor) |
| 480 { | 478 { |
| 481 visitor->trace(m_buffer); | 479 visitor->trace(m_buffer); |
| 482 visitor->trace(m_playbackRate); | 480 visitor->trace(m_playbackRate); |
| 483 AudioScheduledSourceNode::trace(visitor); | 481 AudioScheduledSourceNode::trace(visitor); |
| 484 } | 482 } |
| 485 | 483 |
| 486 } // namespace WebCore | 484 } // namespace WebCore |
| 487 | 485 |
| 488 #endif // ENABLE(WEB_AUDIO) | 486 #endif // ENABLE(WEB_AUDIO) |
| OLD | NEW |