Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: third_party/WebKit/Source/modules/webaudio/AudioBufferSourceNode.cpp

Issue 2389253002: reflow comments in modules/{webaudio,vr} (Closed)
Patch Set: . Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 23 matching lines...) Expand all
34 #include "platform/audio/AudioUtilities.h" 34 #include "platform/audio/AudioUtilities.h"
35 #include "wtf/MathExtras.h" 35 #include "wtf/MathExtras.h"
36 #include "wtf/PtrUtil.h" 36 #include "wtf/PtrUtil.h"
37 #include <algorithm> 37 #include <algorithm>
38 38
39 namespace blink { 39 namespace blink {
40 40
41 const double DefaultGrainDuration = 0.020; // 20ms 41 const double DefaultGrainDuration = 0.020; // 20ms
42 42
43 // Arbitrary upper limit on playback rate. 43 // Arbitrary upper limit on playback rate.
44 // Higher than expected rates can be useful when playing back oversampled buffer s 44 // Higher than expected rates can be useful when playing back oversampled
45 // to minimize linear interpolation aliasing. 45 // buffers to minimize linear interpolation aliasing.
46 const double MaxRate = 1024; 46 const double MaxRate = 1024;
47 47
48 // Number of extra frames to use when determining if a source node can be stoppe d. This should be 48 // Number of extra frames to use when determining if a source node can be
49 // at least one rendering quantum, but we add one more quantum for good measure. This doesn't need 49 // stopped. This should be at least one rendering quantum, but we add one more
50 // to be extra precise, just more than one rendering quantum. See |handleStoppa bleSourceNode()|. 50 // quantum for good measure. This doesn't need to be extra precise, just more
51 // FIXME: Expose the rendering quantum somehow instead of hardwiring a value her e. 51 // than one rendering quantum. See |handleStoppableSourceNode()|.
52 // FIXME: Expose the rendering quantum somehow instead of hardwiring a value
53 // here.
52 const int kExtraStopFrames = 256; 54 const int kExtraStopFrames = 256;
53 55
54 AudioBufferSourceHandler::AudioBufferSourceHandler( 56 AudioBufferSourceHandler::AudioBufferSourceHandler(
55 AudioNode& node, 57 AudioNode& node,
56 float sampleRate, 58 float sampleRate,
57 AudioParamHandler& playbackRate, 59 AudioParamHandler& playbackRate,
58 AudioParamHandler& detune) 60 AudioParamHandler& detune)
59 : AudioScheduledSourceHandler(NodeTypeAudioBufferSource, node, sampleRate), 61 : AudioScheduledSourceHandler(NodeTypeAudioBufferSource, node, sampleRate),
60 m_buffer(nullptr), 62 m_buffer(nullptr),
61 m_playbackRate(playbackRate), 63 m_playbackRate(playbackRate),
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 } 100 }
99 101
100 // The audio thread can't block on this lock, so we call tryLock() instead. 102 // The audio thread can't block on this lock, so we call tryLock() instead.
101 MutexTryLocker tryLocker(m_processLock); 103 MutexTryLocker tryLocker(m_processLock);
102 if (tryLocker.locked()) { 104 if (tryLocker.locked()) {
103 if (!buffer()) { 105 if (!buffer()) {
104 outputBus->zero(); 106 outputBus->zero();
105 return; 107 return;
106 } 108 }
107 109
108 // After calling setBuffer() with a buffer having a different number of chan nels, there can in rare cases be a slight delay 110 // After calling setBuffer() with a buffer having a different number of
109 // before the output bus is updated to the new number of channels because of use of tryLocks() in the context's updating system. 111 // channels, there can in rare cases be a slight delay before the output bus
110 // In this case, if the the buffer has just been changed and we're not quite ready yet, then just output silence. 112 // is updated to the new number of channels because of use of tryLocks() in
113 // the context's updating system. In this case, if the the buffer has just
114 // been changed and we're not quite ready yet, then just output silence.
111 if (numberOfChannels() != buffer()->numberOfChannels()) { 115 if (numberOfChannels() != buffer()->numberOfChannels()) {
112 outputBus->zero(); 116 outputBus->zero();
113 return; 117 return;
114 } 118 }
115 119
116 size_t quantumFrameOffset; 120 size_t quantumFrameOffset;
117 size_t bufferFramesToProcess; 121 size_t bufferFramesToProcess;
118 122
119 updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset, 123 updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset,
120 bufferFramesToProcess); 124 bufferFramesToProcess);
121 125
122 if (!bufferFramesToProcess) { 126 if (!bufferFramesToProcess) {
123 outputBus->zero(); 127 outputBus->zero();
124 return; 128 return;
125 } 129 }
126 130
127 for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i) 131 for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i)
128 m_destinationChannels[i] = outputBus->channel(i)->mutableData(); 132 m_destinationChannels[i] = outputBus->channel(i)->mutableData();
129 133
130 // Render by reading directly from the buffer. 134 // Render by reading directly from the buffer.
131 if (!renderFromBuffer(outputBus, quantumFrameOffset, 135 if (!renderFromBuffer(outputBus, quantumFrameOffset,
132 bufferFramesToProcess)) { 136 bufferFramesToProcess)) {
133 outputBus->zero(); 137 outputBus->zero();
134 return; 138 return;
135 } 139 }
136 140
137 outputBus->clearSilentFlag(); 141 outputBus->clearSilentFlag();
138 } else { 142 } else {
139 // Too bad - the tryLock() failed. We must be in the middle of changing buf fers and were already outputting silence anyway. 143 // Too bad - the tryLock() failed. We must be in the middle of changing
144 // buffers and were already outputting silence anyway.
140 outputBus->zero(); 145 outputBus->zero();
141 } 146 }
142 } 147 }
143 148
144 // Returns true if we're finished. 149 // Returns true if we're finished.
145 bool AudioBufferSourceHandler::renderSilenceAndFinishIfNotLooping( 150 bool AudioBufferSourceHandler::renderSilenceAndFinishIfNotLooping(
146 AudioBus*, 151 AudioBus*,
147 unsigned index, 152 unsigned index,
148 size_t framesToProcess) { 153 size_t framesToProcess) {
149 if (!loop()) { 154 if (!loop()) {
150 // If we're not looping, then stop playing when we get to the end. 155 // If we're not looping, then stop playing when we get to the end.
151 156
152 if (framesToProcess > 0) { 157 if (framesToProcess > 0) {
153 // We're not looping and we've reached the end of the sample data, but we still need to provide more output, 158 // We're not looping and we've reached the end of the sample data, but we
154 // so generate silence for the remaining. 159 // still need to provide more output, so generate silence for the
160 // remaining.
155 for (unsigned i = 0; i < numberOfChannels(); ++i) 161 for (unsigned i = 0; i < numberOfChannels(); ++i)
156 memset(m_destinationChannels[i] + index, 0, 162 memset(m_destinationChannels[i] + index, 0,
157 sizeof(float) * framesToProcess); 163 sizeof(float) * framesToProcess);
158 } 164 }
159 165
160 finish(); 166 finish();
161 return true; 167 return true;
162 } 168 }
163 return false; 169 return false;
164 } 170 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 double bufferSampleRate = buffer()->sampleRate(); 220 double bufferSampleRate = buffer()->sampleRate();
215 221
216 // Avoid converting from time to sample-frames twice by computing 222 // Avoid converting from time to sample-frames twice by computing
217 // the grain end time first before computing the sample frame. 223 // the grain end time first before computing the sample frame.
218 unsigned endFrame = 224 unsigned endFrame =
219 m_isGrain ? AudioUtilities::timeToSampleFrame( 225 m_isGrain ? AudioUtilities::timeToSampleFrame(
220 m_grainOffset + m_grainDuration, bufferSampleRate) 226 m_grainOffset + m_grainDuration, bufferSampleRate)
221 : bufferLength; 227 : bufferLength;
222 228
223 // This is a HACK to allow for HRTF tail-time - avoids glitch at end. 229 // This is a HACK to allow for HRTF tail-time - avoids glitch at end.
224 // FIXME: implement tailTime for each AudioNode for a more general solution to this problem. 230 // FIXME: implement tailTime for each AudioNode for a more general solution to
225 // https://bugs.webkit.org/show_bug.cgi?id=77224 231 // this problem, https://bugs.webkit.org/show_bug.cgi?id=77224
226 if (m_isGrain) 232 if (m_isGrain)
227 endFrame += 512; 233 endFrame += 512;
228 234
229 // Do some sanity checking. 235 // Do some sanity checking.
230 if (endFrame > bufferLength) 236 if (endFrame > bufferLength)
231 endFrame = bufferLength; 237 endFrame = bufferLength;
232 238
233 // If the .loop attribute is true, then values of m_loopStart == 0 && m_loopEn d == 0 implies 239 // If the .loop attribute is true, then values of
234 // that we should use the entire buffer as the loop, otherwise use the loop va lues in m_loopStart and m_loopEnd. 240 // m_loopStart == 0 && m_loopEnd == 0 implies that we should use the entire
241 // buffer as the loop, otherwise use the loop values in m_loopStart and
242 // m_loopEnd.
235 double virtualEndFrame = endFrame; 243 double virtualEndFrame = endFrame;
236 double virtualDeltaFrames = endFrame; 244 double virtualDeltaFrames = endFrame;
237 245
238 if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 && 246 if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 &&
239 m_loopEnd > 0 && m_loopStart < m_loopEnd) { 247 m_loopEnd > 0 && m_loopStart < m_loopEnd) {
240 // Convert from seconds to sample-frames. 248 // Convert from seconds to sample-frames.
241 double loopStartFrame = m_loopStart * buffer()->sampleRate(); 249 double loopStartFrame = m_loopStart * buffer()->sampleRate();
242 double loopEndFrame = m_loopEnd * buffer()->sampleRate(); 250 double loopEndFrame = m_loopEnd * buffer()->sampleRate();
243 251
244 virtualEndFrame = std::min(loopEndFrame, virtualEndFrame); 252 virtualEndFrame = std::min(loopEndFrame, virtualEndFrame);
245 virtualDeltaFrames = virtualEndFrame - loopStartFrame; 253 virtualDeltaFrames = virtualEndFrame - loopStartFrame;
246 } 254 }
247 255
248 // If we're looping and the offset (virtualReadIndex) is past the end of the l oop, wrap back to 256 // If we're looping and the offset (virtualReadIndex) is past the end of the
249 // the beginning of the loop. For other cases, nothing needs to be done. 257 // loop, wrap back to the beginning of the loop. For other cases, nothing
258 // needs to be done.
250 if (loop() && m_virtualReadIndex >= virtualEndFrame) { 259 if (loop() && m_virtualReadIndex >= virtualEndFrame) {
251 m_virtualReadIndex = 260 m_virtualReadIndex =
252 (m_loopStart < 0) ? 0 : (m_loopStart * buffer()->sampleRate()); 261 (m_loopStart < 0) ? 0 : (m_loopStart * buffer()->sampleRate());
253 m_virtualReadIndex = 262 m_virtualReadIndex =
254 std::min(m_virtualReadIndex, static_cast<double>(bufferLength - 1)); 263 std::min(m_virtualReadIndex, static_cast<double>(bufferLength - 1));
255 } 264 }
256 265
257 double computedPlaybackRate = computePlaybackRate(); 266 double computedPlaybackRate = computePlaybackRate();
258 267
259 // Sanity check that our playback rate isn't larger than the loop size. 268 // Sanity check that our playback rate isn't larger than the loop size.
260 if (computedPlaybackRate > virtualDeltaFrames) 269 if (computedPlaybackRate > virtualDeltaFrames)
261 return false; 270 return false;
262 271
263 // Get local copy. 272 // Get local copy.
264 double virtualReadIndex = m_virtualReadIndex; 273 double virtualReadIndex = m_virtualReadIndex;
265 274
266 // Render loop - reading from the source buffer to the destination using linea r interpolation. 275 // Render loop - reading from the source buffer to the destination using
276 // linear interpolation.
267 int framesToProcess = numberOfFrames; 277 int framesToProcess = numberOfFrames;
268 278
269 const float** sourceChannels = m_sourceChannels.get(); 279 const float** sourceChannels = m_sourceChannels.get();
270 float** destinationChannels = m_destinationChannels.get(); 280 float** destinationChannels = m_destinationChannels.get();
271 281
272 DCHECK_GE(virtualReadIndex, 0); 282 DCHECK_GE(virtualReadIndex, 0);
273 DCHECK_GE(virtualDeltaFrames, 0); 283 DCHECK_GE(virtualDeltaFrames, 0);
274 DCHECK_GE(virtualEndFrame, 0); 284 DCHECK_GE(virtualEndFrame, 0);
275 285
276 // Optimize for the very common case of playing back with computedPlaybackRate == 1. 286 // Optimize for the very common case of playing back with
277 // We can avoid the linear interpolation. 287 // computedPlaybackRate == 1. We can avoid the linear interpolation.
278 if (computedPlaybackRate == 1 && 288 if (computedPlaybackRate == 1 &&
279 virtualReadIndex == floor(virtualReadIndex) && 289 virtualReadIndex == floor(virtualReadIndex) &&
280 virtualDeltaFrames == floor(virtualDeltaFrames) && 290 virtualDeltaFrames == floor(virtualDeltaFrames) &&
281 virtualEndFrame == floor(virtualEndFrame)) { 291 virtualEndFrame == floor(virtualEndFrame)) {
282 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); 292 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
283 unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames); 293 unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames);
284 endFrame = static_cast<unsigned>(virtualEndFrame); 294 endFrame = static_cast<unsigned>(virtualEndFrame);
285 while (framesToProcess > 0) { 295 while (framesToProcess > 0) {
286 int framesToEnd = endFrame - readIndex; 296 int framesToEnd = endFrame - readIndex;
287 int framesThisTime = std::min(framesToProcess, framesToEnd); 297 int framesThisTime = std::min(framesToProcess, framesToEnd);
288 framesThisTime = std::max(0, framesThisTime); 298 framesThisTime = std::max(0, framesThisTime);
289 299
290 DCHECK_LE(writeIndex + framesThisTime, destinationLength); 300 DCHECK_LE(writeIndex + framesThisTime, destinationLength);
291 DCHECK_LE(readIndex + framesThisTime, bufferLength); 301 DCHECK_LE(readIndex + framesThisTime, bufferLength);
292 302
293 for (unsigned i = 0; i < numberOfChannels; ++i) 303 for (unsigned i = 0; i < numberOfChannels; ++i)
294 memcpy(destinationChannels[i] + writeIndex, 304 memcpy(destinationChannels[i] + writeIndex,
295 sourceChannels[i] + readIndex, sizeof(float) * framesThisTime); 305 sourceChannels[i] + readIndex, sizeof(float) * framesThisTime);
296 306
297 writeIndex += framesThisTime; 307 writeIndex += framesThisTime;
298 readIndex += framesThisTime; 308 readIndex += framesThisTime;
299 framesToProcess -= framesThisTime; 309 framesToProcess -= framesThisTime;
300 310
301 // It can happen that framesThisTime is 0. DCHECK that we will actually ex it the loop in 311 // It can happen that framesThisTime is 0. DCHECK that we will actually
302 // this case. framesThisTime is 0 only if readIndex >= endFrame; 312 // exit the loop in this case. framesThisTime is 0 only if
313 // readIndex >= endFrame;
303 DCHECK(framesThisTime ? true : readIndex >= endFrame); 314 DCHECK(framesThisTime ? true : readIndex >= endFrame);
304 315
305 // Wrap-around. 316 // Wrap-around.
306 if (readIndex >= endFrame) { 317 if (readIndex >= endFrame) {
307 readIndex -= deltaFrames; 318 readIndex -= deltaFrames;
308 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, 319 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex,
309 framesToProcess)) 320 framesToProcess))
310 break; 321 break;
311 } 322 }
312 } 323 }
313 virtualReadIndex = readIndex; 324 virtualReadIndex = readIndex;
314 } else { 325 } else {
315 while (framesToProcess--) { 326 while (framesToProcess--) {
316 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); 327 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
317 double interpolationFactor = virtualReadIndex - readIndex; 328 double interpolationFactor = virtualReadIndex - readIndex;
318 329
319 // For linear interpolation we need the next sample-frame too. 330 // For linear interpolation we need the next sample-frame too.
320 unsigned readIndex2 = readIndex + 1; 331 unsigned readIndex2 = readIndex + 1;
321 if (readIndex2 >= bufferLength) { 332 if (readIndex2 >= bufferLength) {
322 if (loop()) { 333 if (loop()) {
323 // Make sure to wrap around at the end of the buffer. 334 // Make sure to wrap around at the end of the buffer.
324 readIndex2 = 335 readIndex2 =
325 static_cast<unsigned>(virtualReadIndex + 1 - virtualDeltaFrames); 336 static_cast<unsigned>(virtualReadIndex + 1 - virtualDeltaFrames);
326 } else { 337 } else {
327 readIndex2 = readIndex; 338 readIndex2 = readIndex;
328 } 339 }
329 } 340 }
330 341
331 // Final sanity check on buffer access. 342 // Final sanity check on buffer access.
332 // FIXME: as an optimization, try to get rid of this inner-loop check and put assertions and guards before the loop. 343 // FIXME: as an optimization, try to get rid of this inner-loop check and
344 // put assertions and guards before the loop.
333 if (readIndex >= bufferLength || readIndex2 >= bufferLength) 345 if (readIndex >= bufferLength || readIndex2 >= bufferLength)
334 break; 346 break;
335 347
336 // Linear interpolation. 348 // Linear interpolation.
337 for (unsigned i = 0; i < numberOfChannels; ++i) { 349 for (unsigned i = 0; i < numberOfChannels; ++i) {
338 float* destination = destinationChannels[i]; 350 float* destination = destinationChannels[i];
339 const float* source = sourceChannels[i]; 351 const float* source = sourceChannels[i];
340 352
341 double sample1 = source[readIndex]; 353 double sample1 = source[readIndex];
342 double sample2 = source[readIndex2]; 354 double sample2 = source[readIndex2];
343 double sample = (1.0 - interpolationFactor) * sample1 + 355 double sample = (1.0 - interpolationFactor) * sample1 +
344 interpolationFactor * sample2; 356 interpolationFactor * sample2;
345 357
346 destination[writeIndex] = clampTo<float>(sample); 358 destination[writeIndex] = clampTo<float>(sample);
347 } 359 }
348 writeIndex++; 360 writeIndex++;
349 361
350 virtualReadIndex += computedPlaybackRate; 362 virtualReadIndex += computedPlaybackRate;
351 363
352 // Wrap-around, retaining sub-sample position since virtualReadIndex is fl oating-point. 364 // Wrap-around, retaining sub-sample position since virtualReadIndex is
365 // floating-point.
353 if (virtualReadIndex >= virtualEndFrame) { 366 if (virtualReadIndex >= virtualEndFrame) {
354 virtualReadIndex -= virtualDeltaFrames; 367 virtualReadIndex -= virtualDeltaFrames;
355 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, 368 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex,
356 framesToProcess)) 369 framesToProcess))
357 break; 370 break;
358 } 371 }
359 } 372 }
360 } 373 }
361 374
362 bus->clearSilentFlag(); 375 bus->clearSilentFlag();
363 376
364 m_virtualReadIndex = virtualReadIndex; 377 m_virtualReadIndex = virtualReadIndex;
365 378
366 return true; 379 return true;
367 } 380 }
368 381
369 void AudioBufferSourceHandler::setBuffer(AudioBuffer* buffer, 382 void AudioBufferSourceHandler::setBuffer(AudioBuffer* buffer,
370 ExceptionState& exceptionState) { 383 ExceptionState& exceptionState) {
371 DCHECK(isMainThread()); 384 DCHECK(isMainThread());
372 385
373 if (m_buffer) { 386 if (m_buffer) {
374 exceptionState.throwDOMException( 387 exceptionState.throwDOMException(
375 InvalidStateError, 388 InvalidStateError,
376 "Cannot set buffer after it has been already been set"); 389 "Cannot set buffer after it has been already been set");
377 return; 390 return;
378 } 391 }
379 392
380 // The context must be locked since changing the buffer can re-configure the n umber of channels that are output. 393 // The context must be locked since changing the buffer can re-configure the
394 // number of channels that are output.
381 BaseAudioContext::AutoLocker contextLocker(context()); 395 BaseAudioContext::AutoLocker contextLocker(context());
382 396
383 // This synchronizes with process(). 397 // This synchronizes with process().
384 MutexLocker processLocker(m_processLock); 398 MutexLocker processLocker(m_processLock);
385 399
386 if (buffer) { 400 if (buffer) {
387 // Do any necesssary re-configuration to the buffer's number of channels. 401 // Do any necesssary re-configuration to the buffer's number of channels.
388 unsigned numberOfChannels = buffer->numberOfChannels(); 402 unsigned numberOfChannels = buffer->numberOfChannels();
389 403
390 // This should not be possible since AudioBuffers can't be created with too many channels 404 // This should not be possible since AudioBuffers can't be created with too
391 // either. 405 // many channels either.
392 if (numberOfChannels > BaseAudioContext::maxNumberOfChannels()) { 406 if (numberOfChannels > BaseAudioContext::maxNumberOfChannels()) {
393 exceptionState.throwDOMException( 407 exceptionState.throwDOMException(
394 NotSupportedError, ExceptionMessages::indexOutsideRange( 408 NotSupportedError, ExceptionMessages::indexOutsideRange(
395 "number of input channels", numberOfChannels, 409 "number of input channels", numberOfChannels,
396 1u, ExceptionMessages::InclusiveBound, 410 1u, ExceptionMessages::InclusiveBound,
397 BaseAudioContext::maxNumberOfChannels(), 411 BaseAudioContext::maxNumberOfChannels(),
398 ExceptionMessages::InclusiveBound)); 412 ExceptionMessages::InclusiveBound));
399 return; 413 return;
400 } 414 }
401 415
402 output(0).setNumberOfChannels(numberOfChannels); 416 output(0).setNumberOfChannels(numberOfChannels);
403 417
404 m_sourceChannels = wrapArrayUnique(new const float*[numberOfChannels]); 418 m_sourceChannels = wrapArrayUnique(new const float*[numberOfChannels]);
405 m_destinationChannels = wrapArrayUnique(new float*[numberOfChannels]); 419 m_destinationChannels = wrapArrayUnique(new float*[numberOfChannels]);
406 420
407 for (unsigned i = 0; i < numberOfChannels; ++i) 421 for (unsigned i = 0; i < numberOfChannels; ++i)
408 m_sourceChannels[i] = buffer->getChannelData(i)->data(); 422 m_sourceChannels[i] = buffer->getChannelData(i)->data();
409 423
410 // If this is a grain (as set by a previous call to start()), validate the g rain parameters 424 // If this is a grain (as set by a previous call to start()), validate the
411 // now since it wasn't validated when start was called (because there was no buffer then). 425 // grain parameters now since it wasn't validated when start was called
426 // (because there was no buffer then).
412 if (m_isGrain) 427 if (m_isGrain)
413 clampGrainParameters(buffer); 428 clampGrainParameters(buffer);
414 } 429 }
415 430
416 m_virtualReadIndex = 0; 431 m_virtualReadIndex = 0;
417 m_buffer = buffer; 432 m_buffer = buffer;
418 } 433 }
419 434
420 unsigned AudioBufferSourceHandler::numberOfChannels() { 435 unsigned AudioBufferSourceHandler::numberOfChannels() {
421 return output(0).numberOfChannels(); 436 return output(0).numberOfChannels();
422 } 437 }
423 438
424 void AudioBufferSourceHandler::clampGrainParameters(const AudioBuffer* buffer) { 439 void AudioBufferSourceHandler::clampGrainParameters(const AudioBuffer* buffer) {
425 DCHECK(buffer); 440 DCHECK(buffer);
426 441
427 // We have a buffer so we can clip the offset and duration to lie within the b uffer. 442 // We have a buffer so we can clip the offset and duration to lie within the
443 // buffer.
428 double bufferDuration = buffer->duration(); 444 double bufferDuration = buffer->duration();
429 445
430 m_grainOffset = clampTo(m_grainOffset, 0.0, bufferDuration); 446 m_grainOffset = clampTo(m_grainOffset, 0.0, bufferDuration);
431 447
432 // If the duration was not explicitly given, use the buffer duration to set th e grain 448 // If the duration was not explicitly given, use the buffer duration to set
433 // duration. Otherwise, we want to use the user-specified value, of course. 449 // the grain duration. Otherwise, we want to use the user-specified value, of
450 // course.
434 if (!m_isDurationGiven) 451 if (!m_isDurationGiven)
435 m_grainDuration = bufferDuration - m_grainOffset; 452 m_grainDuration = bufferDuration - m_grainOffset;
436 453
437 if (m_isDurationGiven && loop()) { 454 if (m_isDurationGiven && loop()) {
438 // We're looping a grain with a grain duration specified. Schedule the loop to stop after 455 // We're looping a grain with a grain duration specified. Schedule the loop
439 // grainDuration seconds after starting, possibly running the loop multiple times if 456 // to stop after grainDuration seconds after starting, possibly running the
440 // grainDuration is larger than the buffer duration. The net effect is as if the user called 457 // loop multiple times if grainDuration is larger than the buffer duration.
441 // stop(when + grainDuration). 458 // The net effect is as if the user called stop(when + grainDuration).
442 m_grainDuration = 459 m_grainDuration =
443 clampTo(m_grainDuration, 0.0, std::numeric_limits<double>::infinity()); 460 clampTo(m_grainDuration, 0.0, std::numeric_limits<double>::infinity());
444 m_endTime = m_startTime + m_grainDuration; 461 m_endTime = m_startTime + m_grainDuration;
445 } else { 462 } else {
446 m_grainDuration = 463 m_grainDuration =
447 clampTo(m_grainDuration, 0.0, bufferDuration - m_grainOffset); 464 clampTo(m_grainDuration, 0.0, bufferDuration - m_grainOffset);
448 } 465 }
449 466
450 // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through 467 // We call timeToSampleFrame here since at playbackRate == 1 we don't want to
451 // linear interpolation at a sub-sample position since it will degrade the qua lity. When 468 // go through linear interpolation at a sub-sample position since it will
452 // aligned to the sample-frame the playback will be identical to the PCM data stored in the 469 // degrade the quality. When aligned to the sample-frame the playback will be
453 // buffer. Since playbackRate == 1 is very common, it's worth considering qual ity. 470 // identical to the PCM data stored in the buffer. Since playbackRate == 1 is
471 // very common, it's worth considering quality.
454 m_virtualReadIndex = 472 m_virtualReadIndex =
455 AudioUtilities::timeToSampleFrame(m_grainOffset, buffer->sampleRate()); 473 AudioUtilities::timeToSampleFrame(m_grainOffset, buffer->sampleRate());
456 } 474 }
457 475
458 void AudioBufferSourceHandler::start(double when, 476 void AudioBufferSourceHandler::start(double when,
459 ExceptionState& exceptionState) { 477 ExceptionState& exceptionState) {
460 AudioScheduledSourceHandler::start(when, exceptionState); 478 AudioScheduledSourceHandler::start(when, exceptionState);
461 } 479 }
462 480
463 void AudioBufferSourceHandler::start(double when, 481 void AudioBufferSourceHandler::start(double when,
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 "duration", grainDuration, 0.0)); 528 "duration", grainDuration, 0.0));
511 return; 529 return;
512 } 530 }
513 531
514 // The node is started. Add a reference to keep us alive so that audio 532 // The node is started. Add a reference to keep us alive so that audio
515 // will eventually get played even if Javascript should drop all references 533 // will eventually get played even if Javascript should drop all references
516 // to this node. The reference will get dropped when the source has finished 534 // to this node. The reference will get dropped when the source has finished
517 // playing. 535 // playing.
518 context()->notifySourceNodeStartedProcessing(node()); 536 context()->notifySourceNodeStartedProcessing(node());
519 537
520 // This synchronizes with process(). updateSchedulingInfo will read some of th e variables being 538 // This synchronizes with process(). updateSchedulingInfo will read some of
521 // set here. 539 // the variables being set here.
522 MutexLocker processLocker(m_processLock); 540 MutexLocker processLocker(m_processLock);
523 541
524 m_isDurationGiven = isDurationGiven; 542 m_isDurationGiven = isDurationGiven;
525 m_isGrain = true; 543 m_isGrain = true;
526 m_grainOffset = grainOffset; 544 m_grainOffset = grainOffset;
527 m_grainDuration = grainDuration; 545 m_grainDuration = grainDuration;
528 546
529 // If |when| < currentTime, the source must start now according to the spec. 547 // If |when| < currentTime, the source must start now according to the spec.
530 // So just set startTime to currentTime in this case to start the source now. 548 // So just set startTime to currentTime in this case to start the source now.
531 m_startTime = std::max(when, context()->currentTime()); 549 m_startTime = std::max(when, context()->currentTime());
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
571 m_minPlaybackRate = std::min(finalPlaybackRate, m_minPlaybackRate); 589 m_minPlaybackRate = std::min(finalPlaybackRate, m_minPlaybackRate);
572 590
573 return finalPlaybackRate; 591 return finalPlaybackRate;
574 } 592 }
575 593
576 bool AudioBufferSourceHandler::propagatesSilence() const { 594 bool AudioBufferSourceHandler::propagatesSilence() const {
577 return !isPlayingOrScheduled() || hasFinished() || !m_buffer; 595 return !isPlayingOrScheduled() || hasFinished() || !m_buffer;
578 } 596 }
579 597
580 void AudioBufferSourceHandler::handleStoppableSourceNode() { 598 void AudioBufferSourceHandler::handleStoppableSourceNode() {
581 // If the source node is not looping, and we have a buffer, we can determine w hen the source 599 // If the source node is not looping, and we have a buffer, we can determine
582 // would stop playing. This is intended to handle the (uncommon) scenario whe re start() has 600 // when the source would stop playing. This is intended to handle the
583 // been called but is never connected to the destination (directly or indirect ly). By stopping 601 // (uncommon) scenario where start() has been called but is never connected to
584 // the node, the node can be collected. Otherwise, the node will never get co llected, leaking 602 // the destination (directly or indirectly). By stopping the node, the node
603 // can be collected. Otherwise, the node will never get collected, leaking
585 // memory. 604 // memory.
586 // 605 //
587 // If looping was ever done (m_didSetLooping = true), give up. We can't easil y determine how 606 // If looping was ever done (m_didSetLooping = true), give up. We can't
588 // long we looped so we don't know the actual duration thus far, so don't try to do anything 607 // easily determine how long we looped so we don't know the actual duration
589 // fancy. 608 // thus far, so don't try to do anything fancy.
590 if (!m_didSetLooping && buffer() && isPlayingOrScheduled() && 609 if (!m_didSetLooping && buffer() && isPlayingOrScheduled() &&
591 m_minPlaybackRate > 0) { 610 m_minPlaybackRate > 0) {
592 // Adjust the duration to include the playback rate. Only need to account fo r rate < 1 611 // Adjust the duration to include the playback rate. Only need to account
593 // which makes the sound last longer. For rate >= 1, the source stops soone r, but that's 612 // for rate < 1 which makes the sound last longer. For rate >= 1, the
594 // ok. 613 // source stops sooner, but that's ok.
595 double actualDuration = buffer()->duration() / m_minPlaybackRate; 614 double actualDuration = buffer()->duration() / m_minPlaybackRate;
596 615
597 double stopTime = m_startTime + actualDuration; 616 double stopTime = m_startTime + actualDuration;
598 617
599 // See crbug.com/478301. If a source node is started via start(), the source may not start 618 // See crbug.com/478301. If a source node is started via start(), the source
600 // at that time but one quantum (128 frames) later. But we compute the stop time based on 619 // may not start at that time but one quantum (128 frames) later. But we
601 // the start time and the duration, so we end up stopping one quantum early. Thus, add a 620 // compute the stop time based on the start time and the duration, so we end
602 // little extra time; we just need to stop the source sometime after it shou ld have stopped 621 // up stopping one quantum early. Thus, add a little extra time; we just
603 // if it hadn't already. We don't need to be super precise on when to stop. 622 // need to stop the source sometime after it should have stopped if it
623 // hadn't already. We don't need to be super precise on when to stop.
604 double extraStopTime = 624 double extraStopTime =
605 kExtraStopFrames / static_cast<double>(context()->sampleRate()); 625 kExtraStopFrames / static_cast<double>(context()->sampleRate());
606 626
607 stopTime += extraStopTime; 627 stopTime += extraStopTime;
608 if (context()->currentTime() > stopTime) { 628 if (context()->currentTime() > stopTime) {
609 // The context time has passed the time when the source nodes should have stopped 629 // The context time has passed the time when the source nodes should have
610 // playing. Stop the node now and deref it. (But don't run the onEnded eve nt because the 630 // stopped playing. Stop the node now and deref it. (But don't run the
611 // source never actually played.) 631 // onEnded event because the source never actually played.)
612 finishWithoutOnEnded(); 632 finishWithoutOnEnded();
613 } 633 }
614 } 634 }
615 } 635 }
616 636
617 // ---------------------------------------------------------------- 637 // ----------------------------------------------------------------
618 AudioBufferSourceNode::AudioBufferSourceNode(BaseAudioContext& context) 638 AudioBufferSourceNode::AudioBufferSourceNode(BaseAudioContext& context)
619 : AudioScheduledSourceNode(context), 639 : AudioScheduledSourceNode(context),
620 m_playbackRate(AudioParam::create(context, 640 m_playbackRate(AudioParam::create(context,
621 ParamTypeAudioBufferSourcePlaybackRate, 641 ParamTypeAudioBufferSourcePlaybackRate,
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
735 755
736 void AudioBufferSourceNode::start(double when, 756 void AudioBufferSourceNode::start(double when,
737 double grainOffset, 757 double grainOffset,
738 double grainDuration, 758 double grainDuration,
739 ExceptionState& exceptionState) { 759 ExceptionState& exceptionState) {
740 audioBufferSourceHandler().start(when, grainOffset, grainDuration, 760 audioBufferSourceHandler().start(when, grainOffset, grainDuration,
741 exceptionState); 761 exceptionState);
742 } 762 }
743 763
744 } // namespace blink 764 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698