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

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

Issue 1377903002: Use frames instead of time for running AudioParam timelines. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 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) 2011 Google Inc. All rights reserved. 2 * Copyright (C) 2011 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 * 7 *
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 79
80 exceptionState.throwDOMException( 80 exceptionState.throwDOMException(
81 InvalidAccessError, 81 InvalidAccessError,
82 message + " must be a finite positive number: " + String::number(time)); 82 message + " must be a finite positive number: " + String::number(time));
83 return false; 83 return false;
84 } 84 }
85 85
86 String AudioParamTimeline::eventToString(const ParamEvent& event) 86 String AudioParamTimeline::eventToString(const ParamEvent& event)
87 { 87 {
88 // The default arguments for most automation methods is the value and the ti me. 88 // The default arguments for most automation methods is the value and the ti me.
89 String args = String::number(event.value()) + ", " + String::number(event.ti me(), 16); 89 String args = String::number(event.value()) + ", " + String::number(event.ti me(), 16);
hongchan 2015/10/01 20:20:52 Just out of curiosity, why 16?
Raymond Toy 2015/10/01 20:31:23 That was done in a different CL, unrelated to this
90 90
91 // Get a nice printable name for the event and update the args if necessary. 91 // Get a nice printable name for the event and update the args if necessary.
92 String s; 92 String s;
93 switch (event.type()) { 93 switch (event.type()) {
94 case ParamEvent::SetValue: 94 case ParamEvent::SetValue:
95 s = "setValueAtTime"; 95 s = "setValueAtTime";
96 break; 96 break;
97 case ParamEvent::LinearRampToValue: 97 case ParamEvent::LinearRampToValue:
98 s = "linearRampToValueAtTime"; 98 s = "linearRampToValueAtTime";
99 break; 99 break;
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
252 MutexTryLocker tryLocker(m_eventsLock); 252 MutexTryLocker tryLocker(m_eventsLock);
253 if (!tryLocker.locked() || !context || !m_events.size() || context->curr entTime() < m_events[0].time()) { 253 if (!tryLocker.locked() || !context || !m_events.size() || context->curr entTime() < m_events[0].time()) {
254 hasValue = false; 254 hasValue = false;
255 return defaultValue; 255 return defaultValue;
256 } 256 }
257 } 257 }
258 258
259 // Ask for just a single value. 259 // Ask for just a single value.
260 float value; 260 float value;
261 double sampleRate = context->sampleRate(); 261 double sampleRate = context->sampleRate();
262 double startTime = context->currentTime(); 262 size_t startFrame = context->currentSampleFrame();
263 double endTime = startTime + 1.1 / sampleRate; // time just beyond one sampl e-frame
264 double controlRate = sampleRate / AudioHandler::ProcessingSizeInFrames; // o ne parameter change per render quantum 263 double controlRate = sampleRate / AudioHandler::ProcessingSizeInFrames; // o ne parameter change per render quantum
265 value = valuesForTimeRange(startTime, endTime, defaultValue, &value, 1, samp leRate, controlRate); 264 value = valuesForFrameRange(startFrame, startFrame + 1, defaultValue, &value , 1, sampleRate, controlRate);
266 265
267 hasValue = true; 266 hasValue = true;
268 return value; 267 return value;
269 } 268 }
270 269
271 float AudioParamTimeline::valuesForTimeRange( 270 float AudioParamTimeline::valuesForFrameRange(
272 double startTime, 271 size_t startFrame,
273 double endTime, 272 size_t endFrame,
274 float defaultValue, 273 float defaultValue,
275 float* values, 274 float* values,
276 unsigned numberOfValues, 275 unsigned numberOfValues,
277 double sampleRate, 276 double sampleRate,
278 double controlRate) 277 double controlRate)
279 { 278 {
280 // We can't contend the lock in the realtime audio thread. 279 // We can't contend the lock in the realtime audio thread.
281 MutexTryLocker tryLocker(m_eventsLock); 280 MutexTryLocker tryLocker(m_eventsLock);
282 if (!tryLocker.locked()) { 281 if (!tryLocker.locked()) {
283 if (values) { 282 if (values) {
284 for (unsigned i = 0; i < numberOfValues; ++i) 283 for (unsigned i = 0; i < numberOfValues; ++i)
285 values[i] = defaultValue; 284 values[i] = defaultValue;
286 } 285 }
287 return defaultValue; 286 return defaultValue;
288 } 287 }
289 288
290 return valuesForTimeRangeImpl(startTime, endTime, defaultValue, values, numb erOfValues, sampleRate, controlRate); 289 return valuesForFrameRangeImpl(startFrame, endFrame, defaultValue, values, n umberOfValues, sampleRate, controlRate);
291 } 290 }
292 291
293 float AudioParamTimeline::valuesForTimeRangeImpl( 292 float AudioParamTimeline::valuesForFrameRangeImpl(
294 double startTime, 293 size_t startFrame,
295 double endTime, 294 size_t endFrame,
296 float defaultValue, 295 float defaultValue,
297 float* values, 296 float* values,
298 unsigned numberOfValues, 297 unsigned numberOfValues,
299 double sampleRate, 298 double sampleRate,
300 double controlRate) 299 double controlRate)
301 { 300 {
302 ASSERT(values); 301 ASSERT(values);
303 if (!values) 302 if (!values)
304 return defaultValue; 303 return defaultValue;
305 304
306 // Return default value if there are no events matching the desired time ran ge. 305 // Return default value if there are no events matching the desired time ran ge.
307 if (!m_events.size() || endTime <= m_events[0].time()) { 306 if (!m_events.size() || (endFrame / sampleRate <= m_events[0].time())) {
308 for (unsigned i = 0; i < numberOfValues; ++i) 307 for (unsigned i = 0; i < numberOfValues; ++i)
309 values[i] = defaultValue; 308 values[i] = defaultValue;
310 return defaultValue; 309 return defaultValue;
311 } 310 }
312 311
313 // Maintain a running time and index for writing the values buffer. 312 // Maintain a running time (frame) and index for writing the values buffer.
314 double currentTime = startTime; 313 size_t currentFrame = startFrame;
315 unsigned writeIndex = 0; 314 unsigned writeIndex = 0;
316 315
317 // If first event is after startTime then fill initial part of values buffer with defaultValue 316 // If first event is after startFrame then fill initial part of values buffe r with defaultValue
318 // until we reach the first event time. 317 // until we reach the first event time.
319 double firstEventTime = m_events[0].time(); 318 double firstEventTime = m_events[0].time();
320 if (firstEventTime > startTime) { 319 if (firstEventTime > startFrame / sampleRate) {
321 double fillToTime = std::min(endTime, firstEventTime); 320 // |fillToFrame| is an exclusive upper bound, so use ceil() to compute t he bound from the
322 unsigned fillToFrame = AudioUtilities::timeToSampleFrame(fillToTime - st artTime, sampleRate); 321 // firstEventTime.
323 fillToFrame = std::min(fillToFrame, numberOfValues); 322 size_t fillToFrame = std::min(endFrame, static_cast<size_t>(ceil(firstEv entTime * sampleRate)));
323 ASSERT(fillToFrame >= startFrame);
324 fillToFrame -= startFrame;
325 fillToFrame = std::min(fillToFrame, static_cast<size_t>(numberOfValues)) ;
324 for (; writeIndex < fillToFrame; ++writeIndex) 326 for (; writeIndex < fillToFrame; ++writeIndex)
325 values[writeIndex] = defaultValue; 327 values[writeIndex] = defaultValue;
326 328
327 currentTime = fillToTime; 329 currentFrame += fillToFrame;
328 } 330 }
329 331
330 float value = defaultValue; 332 float value = defaultValue;
331 333
332 // Go through each event and render the value buffer where the times overlap , 334 // Go through each event and render the value buffer where the times overlap ,
333 // stopping when we've rendered all the requested values. 335 // stopping when we've rendered all the requested values.
334 // FIXME: could try to optimize by avoiding having to iterate starting from the very first event 336 // FIXME: could try to optimize by avoiding having to iterate starting from the very first event
335 // and keeping track of a "current" event index. 337 // and keeping track of a "current" event index.
336 int n = m_events.size(); 338 int n = m_events.size();
337 for (int i = 0; i < n && writeIndex < numberOfValues; ++i) { 339 for (int i = 0; i < n && writeIndex < numberOfValues; ++i) {
338 ParamEvent& event = m_events[i]; 340 ParamEvent& event = m_events[i];
339 ParamEvent* nextEvent = i < n - 1 ? &(m_events[i + 1]) : 0; 341 ParamEvent* nextEvent = i < n - 1 ? &(m_events[i + 1]) : 0;
340 342
341 // Wait until we get a more recent event. 343 // Wait until we get a more recent event.
342 if (nextEvent && nextEvent->time() < currentTime) 344 if (nextEvent && nextEvent->time() < currentFrame / sampleRate) {
343 continue; 345 // But if the current event is a SetValue event and the event time i s between
346 // currentFrame - 1 and curentFrame (in time). we don't want to skip it. If we do skip
347 // it, the SetValue event is completely skipped and not applied, whi ch is wrong. Other
348 // events don't have this problem. (Because currentFrame is unsigne d, we do the time
349 // check in this funny, but equivalent way.)
350 double eventFrame = event.time() * sampleRate;
351
352 // Condition is currentFrame - 1 < eventFrame <= currentFrame, but c urrentFrame is
353 // unsigned and could be 0, so use currentFrame < eventFrame + 1 ins tead.
354 if (!((event.type() == ParamEvent::SetValue
355 && (eventFrame <= currentFrame)
356 && (currentFrame < eventFrame + 1))))
357 continue;
358 }
344 359
345 float value1 = event.value(); 360 float value1 = event.value();
346 double time1 = event.time(); 361 double time1 = event.time();
347 float value2 = nextEvent ? nextEvent->value() : value1; 362 float value2 = nextEvent ? nextEvent->value() : value1;
348 double time2 = nextEvent ? nextEvent->time() : endTime + 1; 363 double time2 = nextEvent ? nextEvent->time() : endFrame / sampleRate + 1 ;
349 364
350 double deltaTime = time2 - time1; 365 double deltaTime = time2 - time1;
351 float k = deltaTime > 0 ? 1 / deltaTime : 0; 366 float k = deltaTime > 0 ? 1 / deltaTime : 0;
352 double sampleFrameTimeIncr = 1 / sampleRate;
353 367
354 double fillToTime = std::min(endTime, time2); 368 // |fillToEndFrame| is the exclusive upper bound of the last frame to be computed for this
355 unsigned fillToFrame = AudioUtilities::timeToSampleFrame(fillToTime - st artTime, sampleRate); 369 // event. It's either the last desired frame (|endFrame|) or derived fr om the end time of
356 fillToFrame = std::min(fillToFrame, numberOfValues); 370 // the next event (time2). We compute ceil(time2*sampleRate) because fil lToEndFrame is the
371 // exclusive upper bound. Consider the case where |startFrame| = 128 an d time2 = 128.1
372 // (assuming sampleRate = 1). Since time2 is greater than 128, we want to output a value
373 // for frame 128. This requires that fillToEndFrame be at least 129. T his is achieved by
374 // ceil(time2).
375 size_t fillToEndFrame = std::min(endFrame, static_cast<size_t>(ceil(time 2 * sampleRate)));
376 ASSERT(fillToEndFrame >= startFrame);
377 size_t fillToFrame = fillToEndFrame - startFrame;
378 fillToFrame = std::min(fillToFrame, static_cast<size_t>(numberOfValues)) ;
357 379
358 ParamEvent::Type nextEventType = nextEvent ? static_cast<ParamEvent::Typ e>(nextEvent->type()) : ParamEvent::LastType /* unknown */; 380 ParamEvent::Type nextEventType = nextEvent ? static_cast<ParamEvent::Typ e>(nextEvent->type()) : ParamEvent::LastType /* unknown */;
359 381
360 // First handle linear and exponential ramps which require looking ahead to the next event. 382 // First handle linear and exponential ramps which require looking ahead to the next event.
361 if (nextEventType == ParamEvent::LinearRampToValue) { 383 if (nextEventType == ParamEvent::LinearRampToValue) {
362 const float valueDelta = value2 - value1; 384 const float valueDelta = value2 - value1;
363 #if CPU(X86) || CPU(X86_64) 385 #if CPU(X86) || CPU(X86_64)
364 // Minimize in-loop operations. Calculate starting value and increme nt. Next step: value += inc. 386 // Minimize in-loop operations. Calculate starting value and increme nt. Next step: value += inc.
365 // value = value1 + (currentTime - time1) * k * (value2 - value1); 387 // value = value1 + (currentFrame/sampleRate - time1) * k * (value2 - value1);
366 // inc = sampleFrameTimeIncr * k * (value2 - value1); 388 // inc = 4 / sampleRate * k * (value2 - value1);
367 // Resolve recursion by expanding constants to achieve a 4-step loop unrolling. 389 // Resolve recursion by expanding constants to achieve a 4-step loop unrolling.
368 // value = value1 + ((currentTime - time1) + i * sampleFrameTimeInc r) * k * (value2 -value1), i in 0..3 390 // value = value1 + ((currentFrame/sampleRate - time1) + i * sample FrameTimeIncr) * k * (value2 -value1), i in 0..3
369 __m128 vValue = _mm_mul_ps(_mm_set_ps1(sampleFrameTimeIncr), _mm_set _ps(3, 2, 1, 0)); 391 __m128 vValue = _mm_mul_ps(_mm_set_ps1(1 / sampleRate), _mm_set_ps(3 , 2, 1, 0));
370 vValue = _mm_add_ps(vValue, _mm_set_ps1(currentTime - time1)); 392 vValue = _mm_add_ps(vValue, _mm_set_ps1(currentFrame / sampleRate - time1));
371 vValue = _mm_mul_ps(vValue, _mm_set_ps1(k * valueDelta)); 393 vValue = _mm_mul_ps(vValue, _mm_set_ps1(k * valueDelta));
372 vValue = _mm_add_ps(vValue, _mm_set_ps1(value1)); 394 vValue = _mm_add_ps(vValue, _mm_set_ps1(value1));
373 __m128 vInc = _mm_set_ps1(4 * sampleFrameTimeIncr * k * valueDelta); 395 __m128 vInc = _mm_set_ps1(4 / sampleRate * k * valueDelta);
374 396
375 // Truncate loop steps to multiple of 4. 397 // Truncate loop steps to multiple of 4.
376 unsigned fillToFrameTrunc = writeIndex + ((fillToFrame - writeIndex) / 4) * 4; 398 unsigned fillToFrameTrunc = writeIndex + ((fillToFrame - writeIndex) / 4) * 4;
377 // Compute final time. 399 // Compute final time.
378 currentTime += sampleFrameTimeIncr * (fillToFrameTrunc - writeIndex) ; 400 currentFrame += fillToFrameTrunc - writeIndex;
401
379 // Process 4 loop steps. 402 // Process 4 loop steps.
380 for (; writeIndex < fillToFrameTrunc; writeIndex += 4) { 403 for (; writeIndex < fillToFrameTrunc; writeIndex += 4) {
381 _mm_storeu_ps(values + writeIndex, vValue); 404 _mm_storeu_ps(values + writeIndex, vValue);
382 vValue = _mm_add_ps(vValue, vInc); 405 vValue = _mm_add_ps(vValue, vInc);
383 } 406 }
384 #endif 407 #endif
385 // Serially process remaining values. 408 // Serially process remaining values.
386 for (; writeIndex < fillToFrame; ++writeIndex) { 409 for (; writeIndex < fillToFrame; ++writeIndex) {
387 float x = (currentTime - time1) * k; 410 float x = (currentFrame / sampleRate - time1) * k;
388 // value = (1 - x) * value1 + x * value2; 411 // value = (1 - x) * value1 + x * value2;
389 value = value1 + x * valueDelta; 412 value = value1 + x * valueDelta;
390 values[writeIndex] = value; 413 values[writeIndex] = value;
391 currentTime += sampleFrameTimeIncr; 414 ++currentFrame;
392 } 415 }
393 } else if (nextEventType == ParamEvent::ExponentialRampToValue) { 416 } else if (nextEventType == ParamEvent::ExponentialRampToValue) {
394 if (value1 <= 0 || value2 <= 0) { 417 if (value1 <= 0 || value2 <= 0) {
395 // Handle negative values error case by propagating previous val ue. 418 // Handle negative values error case by propagating previous val ue.
396 for (; writeIndex < fillToFrame; ++writeIndex) 419 for (; writeIndex < fillToFrame; ++writeIndex)
397 values[writeIndex] = value; 420 values[writeIndex] = value;
398 } else { 421 } else {
399 float numSampleFrames = deltaTime * sampleRate; 422 float numSampleFrames = deltaTime * sampleRate;
400 // The value goes exponentially from value1 to value2 in a durat ion of deltaTime seconds (corresponding to numSampleFrames). 423 // The value goes exponentially from value1 to value2 in a durat ion of deltaTime
424 // seconds according to
425 //
426 // v(t) = v1*(v2/v1)^((t-t1)/(t2-t1))
427 //
428 // Let c be currentFrame and F be the sampleRate. Then we want to sample v(t)
429 // at times t = (c + k)/F for k = 0, 1, ...:
430 //
431 // v((c+k)/F) = v1*(v2/v1)^(((c/F+k/F)-t1)/(t2-t1))
432 // = v1*(v2/v1)^((c/F-t1)/(t2-t1))
433 // *(v2/v1)^((k/F)/(t2-t1))
434 // = v1*(v2/v1)^((c/F-t1)/(t2-t1))
435 // *[(v2/v1)^(1/(F*(t2-t1)))]^k
436 //
437 // Thus, this can be written as
438 //
439 // v((c+k)/F) = V*m^k
440 //
441 // where
442 // V = v1*(v2/v1)^((c/F-t1)/(t2-t1))
443 // m = (v2/v1)^(1/(F*(t2-t1)))
444
401 // Compute the per-sample multiplier. 445 // Compute the per-sample multiplier.
402 float multiplier = powf(value2 / value1, 1 / numSampleFrames); 446 float multiplier = powf(value2 / value1, 1 / numSampleFrames);
403 447 // Set the starting value of the exponential ramp.
404 // Set the starting value of the exponential ramp. This is the s ame as multiplier ^
405 // AudioUtilities::timeToSampleFrame(currentTime - time1, sample Rate), but is more
406 // accurate, especially if multiplier is close to 1.
407 value = value1 * powf(value2 / value1, 448 value = value1 * powf(value2 / value1,
408 AudioUtilities::timeToSampleFrame(currentTime - time1, sampl eRate) / numSampleFrames); 449 (currentFrame / sampleRate - time1) / deltaTime);
409 450
410 for (; writeIndex < fillToFrame; ++writeIndex) { 451 for (; writeIndex < fillToFrame; ++writeIndex) {
411 values[writeIndex] = value; 452 values[writeIndex] = value;
412 value *= multiplier; 453 value *= multiplier;
413 currentTime += sampleFrameTimeIncr; 454 ++currentFrame;
414 } 455 }
415 } 456 }
416 } else { 457 } else {
417 // Handle event types not requiring looking ahead to the next event. 458 // Handle event types not requiring looking ahead to the next event.
418 switch (event.type()) { 459 switch (event.type()) {
419 case ParamEvent::SetValue: 460 case ParamEvent::SetValue:
420 case ParamEvent::LinearRampToValue: 461 case ParamEvent::LinearRampToValue:
421 case ParamEvent::ExponentialRampToValue: 462 case ParamEvent::ExponentialRampToValue:
422 { 463 {
423 currentTime = fillToTime; 464 currentFrame = fillToEndFrame;
424 465
425 // Simply stay at a constant value. 466 // Simply stay at a constant value.
426 value = event.value(); 467 value = event.value();
427 for (; writeIndex < fillToFrame; ++writeIndex) 468 for (; writeIndex < fillToFrame; ++writeIndex)
428 values[writeIndex] = value; 469 values[writeIndex] = value;
429 470
430 break; 471 break;
431 } 472 }
432 473
433 case ParamEvent::SetTarget: 474 case ParamEvent::SetTarget:
434 { 475 {
435 currentTime = fillToTime; 476 // Exponential approach to target value with given time cons tant.
477 //
478 // v(t) = v2 + (v1 - v2)*exp(-(t-t1/tau))
479 //
436 480
437 // Exponential approach to target value with given time cons tant.
438 float target = event.value(); 481 float target = event.value();
439 float timeConstant = event.timeConstant(); 482 float timeConstant = event.timeConstant();
440 float discreteTimeConstant = static_cast<float>(AudioUtiliti es::discreteTimeConstantForSampleRate(timeConstant, controlRate)); 483 float discreteTimeConstant = static_cast<float>(AudioUtiliti es::discreteTimeConstantForSampleRate(timeConstant, controlRate));
441 484
485 // Set the starting value correctly. This is only needed wh en the current time
486 // is "equal" to the start time of this event. This is to g et the sampling
487 // correct if the start time of this automation isn't on a f rame boundary.
488 // Otherwise, we can just continue from where we left off fr om the previous
489 // rendering quantum.
490
491 {
492 double rampStartFrame = time1 * sampleRate;
493 // Condition is c - 1 < r <= c where c = currentFrame an d r =
494 // rampStartFrame. Compute it this way because currentF rame is unsigned and
495 // could be 0.
496 if (rampStartFrame <= currentFrame && currentFrame < ram pStartFrame + 1)
497 value = target + (value - target) * exp(-(currentFra me / sampleRate - time1) / timeConstant);
498 }
442 #if CPU(X86) || CPU(X86_64) 499 #if CPU(X86) || CPU(X86_64)
443 // Resolve recursion by expanding constants to achieve a 4-s tep loop unrolling. 500 // Resolve recursion by expanding constants to achieve a 4-s tep loop unrolling.
444 // v1 = v0 + (t - v0) * c 501 // v1 = v0 + (t - v0) * c
445 // v2 = v1 + (t - v1) * c 502 // v2 = v1 + (t - v1) * c
446 // v2 = v0 + (t - v0) * c + (t - (v0 + (t - v0) * c)) * c 503 // v2 = v0 + (t - v0) * c + (t - (v0 + (t - v0) * c)) * c
447 // v2 = v0 + (t - v0) * c + (t - v0) * c - (t - v0) * c * c 504 // v2 = v0 + (t - v0) * c + (t - v0) * c - (t - v0) * c * c
448 // v2 = v0 + (t - v0) * c * (2 - c) 505 // v2 = v0 + (t - v0) * c * (2 - c)
449 // Thus c0 = c, c1 = c*(2-c). The same logic applies to c2 a nd c3. 506 // Thus c0 = c, c1 = c*(2-c). The same logic applies to c2 a nd c3.
450 const float c0 = discreteTimeConstant; 507 const float c0 = discreteTimeConstant;
451 const float c1 = c0 * (2 - c0); 508 const float c1 = c0 * (2 - c0);
(...skipping 17 matching lines...) Expand all
469 // Update value for next iteration. 526 // Update value for next iteration.
470 value += delta * c3; 527 value += delta * c3;
471 } 528 }
472 #endif 529 #endif
473 // Serially process remaining values 530 // Serially process remaining values
474 for (; writeIndex < fillToFrame; ++writeIndex) { 531 for (; writeIndex < fillToFrame; ++writeIndex) {
475 values[writeIndex] = value; 532 values[writeIndex] = value;
476 value += (target - value) * discreteTimeConstant; 533 value += (target - value) * discreteTimeConstant;
477 } 534 }
478 535
536 currentFrame = fillToEndFrame;
537
479 break; 538 break;
480 } 539 }
481 540
482 case ParamEvent::SetValueCurve: 541 case ParamEvent::SetValueCurve:
483 { 542 {
484 DOMFloat32Array* curve = event.curve(); 543 DOMFloat32Array* curve = event.curve();
485 float* curveData = curve ? curve->data() : 0; 544 float* curveData = curve ? curve->data() : 0;
486 unsigned numberOfCurvePoints = curve ? curve->length() : 0; 545 unsigned numberOfCurvePoints = curve ? curve->length() : 0;
487 546
488 // Curve events have duration, so don't just use next event time. 547 // Curve events have duration, so don't just use next event time.
489 double duration = event.duration(); 548 double duration = event.duration();
490 double durationFrames = duration * sampleRate; 549 double durationFrames = duration * sampleRate;
491 // How much to step the curve index for each frame. We want the curve index to 550 // How much to step the curve index for each frame. We want the curve index to
492 // be exactly equal to the last index (numberOfCurvePoints - 1) after 551 // be exactly equal to the last index (numberOfCurvePoints - 1) after
493 // durationFrames - 1 frames. In this way, the last output value will equal the 552 // durationFrames - 1 frames. In this way, the last output value will equal the
494 // last value in the curve array. 553 // last value in the curve array.
495 double curvePointsPerFrame; 554 double curvePointsPerFrame;
496 555
497 // If the duration is less than a frame, we want to just out put the last curve 556 // If the duration is less than a frame, we want to just out put the last curve
498 // value. Do this by setting curvePointsPerFrame to be more than number of 557 // value. Do this by setting curvePointsPerFrame to be more than number of
499 // points in the curve. Then the curveVirtualIndex will alw ays exceed the last 558 // points in the curve. Then the curveVirtualIndex will alw ays exceed the last
500 // curve index, so that the last curve value will be used. 559 // curve index, so that the last curve value will be used.
501 if (durationFrames > 1) 560 if (durationFrames > 1)
502 curvePointsPerFrame = (numberOfCurvePoints - 1) / (durat ionFrames - 1); 561 curvePointsPerFrame = (numberOfCurvePoints - 1) / (durat ionFrames - 1);
503 else 562 else
504 curvePointsPerFrame = numberOfCurvePoints + 1; 563 curvePointsPerFrame = numberOfCurvePoints + 1;
505 564
506 if (!curve || !curveData || !numberOfCurvePoints || duration <= 0 || sampleRate <= 0) { 565 if (!curve || !curveData || !numberOfCurvePoints || duration <= 0 || sampleRate <= 0) {
507 // Error condition - simply propagate previous value. 566 // Error condition - simply propagate previous value.
508 currentTime = fillToTime; 567 currentFrame = fillToEndFrame;
509 for (; writeIndex < fillToFrame; ++writeIndex) 568 for (; writeIndex < fillToFrame; ++writeIndex)
510 values[writeIndex] = value; 569 values[writeIndex] = value;
511 break; 570 break;
512 } 571 }
513 572
514 // Save old values and recalculate information based on the curve's duration 573 // Save old values and recalculate information based on the curve's duration
515 // instead of the next event time. 574 // instead of the next event time.
516 unsigned nextEventFillToFrame = fillToFrame; 575 size_t nextEventFillToFrame = fillToFrame;
517 double nextEventFillToTime = fillToTime; 576
518 fillToTime = std::min(endTime, time1 + duration); 577 // Use ceil here for the same reason as using ceil above: fi llToEndFrame is an
519 // |fillToTime| can be less than |startTime| when the end of the 578 // exclusive upper bound of the last frame to be computed.
579 fillToEndFrame = std::min(endFrame, static_cast<size_t>(ceil (sampleRate*(time1 + duration))));
580 // |fillToFrame| can be less than |startFrame| when the end of the
520 // setValueCurve automation has been reached, but the next a utomation has not 581 // setValueCurve automation has been reached, but the next a utomation has not
521 // yet started. In this case, |fillToTime| is clipped to |ti me1|+|duration| 582 // yet started. In this case, |fillToFrame| is clipped to |t ime1|+|duration|
522 // above, but |startTime| will keep increasing (because the current time is 583 // above, but |startFrame| will keep increasing (because the current time is
523 // increasing). 584 // increasing).
524 fillToFrame = AudioUtilities::timeToSampleFrame(std::max(0.0 , fillToTime - startTime), sampleRate); 585 fillToFrame = (fillToEndFrame < startFrame) ? 0 : fillToEndF rame - startFrame;
525 fillToFrame = std::min(fillToFrame, numberOfValues); 586 fillToFrame = std::min(fillToFrame, static_cast<size_t>(numb erOfValues));
526 587
527 // Index into the curve data using a floating-point value. 588 // Index into the curve data using a floating-point value.
528 // We're scaling the number of curve points by the duration (see curvePointsPerFrame). 589 // We're scaling the number of curve points by the duration (see curvePointsPerFrame).
529 double curveVirtualIndex = 0; 590 double curveVirtualIndex = 0;
530 if (time1 < currentTime) { 591 if (time1 < currentFrame / sampleRate) {
531 // Index somewhere in the middle of the curve data. 592 // Index somewhere in the middle of the curve data.
532 // Don't use timeToSampleFrame() since we want the exact floating-point frame. 593 // Don't use timeToSampleFrame() since we want the exact floating-point frame.
533 double frameOffset = (currentTime - time1) * sampleRate; 594 double frameOffset = currentFrame - time1 * sampleRate;
534 curveVirtualIndex = curvePointsPerFrame * frameOffset; 595 curveVirtualIndex = curvePointsPerFrame * frameOffset;
535 } 596 }
536 597
537 // Set the default value in case fillToFrame is 0. 598 // Set the default value in case fillToFrame is 0.
538 value = curveData[numberOfCurvePoints - 1]; 599 value = curveData[numberOfCurvePoints - 1];
539 600
540 // Render the stretched curve data using linear interpolatio n. Oversampled 601 // Render the stretched curve data using linear interpolatio n. Oversampled
541 // curve data can be provided if sharp discontinuities are d esired. 602 // curve data can be provided if sharp discontinuities are d esired.
542 unsigned k = 0; 603 unsigned k = 0;
543 #if CPU(X86) || CPU(X86_64) 604 #if CPU(X86) || CPU(X86_64)
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 } else { 658 } else {
598 curveIndex0 = numberOfCurvePoints - 1; 659 curveIndex0 = numberOfCurvePoints - 1;
599 } 660 }
600 661
601 unsigned curveIndex1 = std::min(curveIndex0 + 1, numberO fCurvePoints - 1); 662 unsigned curveIndex1 = std::min(curveIndex0 + 1, numberO fCurvePoints - 1);
602 663
603 // Linearly interpolate between the two nearest curve po ints. |delta| is 664 // Linearly interpolate between the two nearest curve po ints. |delta| is
604 // clamped to 1 because currentVirtualIndex can exceed c urveIndex0 by more 665 // clamped to 1 because currentVirtualIndex can exceed c urveIndex0 by more
605 // than one. This can happen when we reached the end of the curve but still 666 // than one. This can happen when we reached the end of the curve but still
606 // need values to fill out the current rendering quantum . 667 // need values to fill out the current rendering quantum .
668 ASSERT(curveIndex0 < numberOfCurvePoints);
669 ASSERT(curveIndex1 < numberOfCurvePoints);
607 float c0 = curveData[curveIndex0]; 670 float c0 = curveData[curveIndex0];
608 float c1 = curveData[curveIndex1]; 671 float c1 = curveData[curveIndex1];
609 double delta = std::min(currentVirtualIndex - curveIndex 0, 1.0); 672 double delta = std::min(currentVirtualIndex - curveIndex 0, 1.0);
610 673
611 value = c0 + (c1 - c0) * delta; 674 value = c0 + (c1 - c0) * delta;
612 675
613 values[writeIndex] = value; 676 values[writeIndex] = value;
614 } 677 }
615 678
616 // If there's any time left after the duration of this event and the start 679 // If there's any time left after the duration of this event and the start
617 // of the next, then just propagate the last value. 680 // of the next, then just propagate the last value of the cu rveData.
681 value = curveData[numberOfCurvePoints - 1];
618 for (; writeIndex < nextEventFillToFrame; ++writeIndex) 682 for (; writeIndex < nextEventFillToFrame; ++writeIndex)
619 values[writeIndex] = value; 683 values[writeIndex] = value;
620 684
621 // Re-adjust current time 685 // Re-adjust current time
622 currentTime = nextEventFillToTime; 686 currentFrame = nextEventFillToFrame;
623 687
624 break; 688 break;
625 } 689 }
626 case ParamEvent::LastType: 690 case ParamEvent::LastType:
627 ASSERT_NOT_REACHED(); 691 ASSERT_NOT_REACHED();
628 break; 692 break;
629 } 693 }
630 } 694 }
631 } 695 }
632 696
633 // If there's any time left after processing the last event then just propag ate the last value 697 // If there's any time left after processing the last event then just propag ate the last value
634 // to the end of the values buffer. 698 // to the end of the values buffer.
635 for (; writeIndex < numberOfValues; ++writeIndex) 699 for (; writeIndex < numberOfValues; ++writeIndex)
636 values[writeIndex] = value; 700 values[writeIndex] = value;
637 701
638 return value; 702 return value;
639 } 703 }
640 704
641 } // namespace blink 705 } // namespace blink
642 706
643 #endif // ENABLE(WEB_AUDIO) 707 #endif // ENABLE(WEB_AUDIO)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698