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 |