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

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

Issue 1485003002: Make setTarget followed by linear or exponential ramp continuous. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase and fix test failures Created 4 years, 7 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
« no previous file with comments | « third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 402 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 double eventFrame = event.time() * sampleRate; 413 double eventFrame = event.time() * sampleRate;
414 414
415 // Condition is currentFrame - 1 < eventFrame <= currentFrame, but c urrentFrame is 415 // Condition is currentFrame - 1 < eventFrame <= currentFrame, but c urrentFrame is
416 // unsigned and could be 0, so use currentFrame < eventFrame + 1 ins tead. 416 // unsigned and could be 0, so use currentFrame < eventFrame + 1 ins tead.
417 if (!((event.getType() == ParamEvent::SetValue 417 if (!((event.getType() == ParamEvent::SetValue
418 && (eventFrame <= currentFrame) 418 && (eventFrame <= currentFrame)
419 && (currentFrame < eventFrame + 1)))) 419 && (currentFrame < eventFrame + 1))))
420 continue; 420 continue;
421 } 421 }
422 422
423 // If there's no next event, set nextEventType to LastType to indicate t hat.
424 ParamEvent::Type nextEventType = nextEvent ? static_cast<ParamEvent::Typ e>(nextEvent->getType()) : ParamEvent::LastType;
425
426 // If the current event is SetTarget and the next event is a LinearRampT oValue or
427 // ExponentialRampToValue, special handling is needed. In this case, th e linear and
428 // exponential ramp should start at wherever the SetTarget processing ha s reached.
429 if (event.getType() == ParamEvent::SetTarget
430 && (nextEventType == ParamEvent::LinearRampToValue
431 || nextEventType == ParamEvent::ExponentialRampToValue)) {
432 // Replace the SetTarget with a SetValue to set the starting time an d value for the ramp
433 // using the current frame. We need to update |value| appropriately depending on
434 // whether the ramp has started or not.
435 //
436 // If SetTarget starts somewhere between currentFrame - 1 and curren tFrame, we directly
437 // compute the value it would have at currentFrame. If not, we upda te the value from
438 // the value from currentFrame - 1.
439 //
440 // Can't use the condition currentFrame - 1 <= t0 * sampleRate <= cu rrentFrame because
441 // currentFrame is unsigned and could be 0. Instead, compute the co ndition this way,
442 // where f = currentFrame and Fs = sampleRate:
443 //
444 // f - 1 <= t0 * Fs <= f
445 // 2 * f - 2 <= 2 * Fs * t0 <= 2 * f
446 // -2 <= 2 * Fs * t0 - 2 * f <= 0
447 // -1 <= 2 * Fs * t0 - 2 * f + 1 <= 1
448 // abs(2 * Fs * t0 - 2 * f + 1) <= 1
449 if (fabs(2 * sampleRate * event.time() - 2 * currentFrame + 1) <= 1) {
450 // SetTarget is starting somewhere between currentFrame - 1 and
451 // currentFrame. Compute the value the SetTarget would have at t he currentFrame.
452 value = event.value() + (value - event.value()) * exp(-(currentF rame / sampleRate - event.time()) / event.timeConstant());
453 } else {
454 // SetTarget has already started. Update |value| one frame beca use it's the value from
455 // the previous frame.
456 float discreteTimeConstant = static_cast<float>(AudioUtilities:: discreteTimeConstantForSampleRate(
457 event.timeConstant(), controlRate));
458 value += (event.value() - value) * discreteTimeConstant;
459 }
460 m_events[i] = ParamEvent::createSetValueEvent(value, currentFrame / sampleRate);
461 }
462
423 float value1 = event.value(); 463 float value1 = event.value();
424 double time1 = event.time(); 464 double time1 = event.time();
425 465
426 float value2 = nextEvent ? nextEvent->value() : value1; 466 float value2 = nextEvent ? nextEvent->value() : value1;
427 double time2 = nextEvent ? nextEvent->time() : endFrame / sampleRate + 1 ; 467 double time2 = nextEvent ? nextEvent->time() : endFrame / sampleRate + 1 ;
428 468
429 double deltaTime = time2 - time1; 469 double deltaTime = time2 - time1;
430 float k = deltaTime > 0 ? 1 / deltaTime : 0; 470 float k = deltaTime > 0 ? 1 / deltaTime : 0;
431 471
432 // |fillToEndFrame| is the exclusive upper bound of the last frame to be computed for this 472 // |fillToEndFrame| is the exclusive upper bound of the last frame to be computed for this
433 // event. It's either the last desired frame (|endFrame|) or derived fr om the end time of 473 // event. It's either the last desired frame (|endFrame|) or derived fr om the end time of
434 // the next event (time2). We compute ceil(time2*sampleRate) because fil lToEndFrame is the 474 // the next event (time2). We compute ceil(time2*sampleRate) because fil lToEndFrame is the
435 // exclusive upper bound. Consider the case where |startFrame| = 128 an d time2 = 128.1 475 // exclusive upper bound. Consider the case where |startFrame| = 128 an d time2 = 128.1
436 // (assuming sampleRate = 1). Since time2 is greater than 128, we want to output a value 476 // (assuming sampleRate = 1). Since time2 is greater than 128, we want to output a value
437 // for frame 128. This requires that fillToEndFrame be at least 129. T his is achieved by 477 // for frame 128. This requires that fillToEndFrame be at least 129. T his is achieved by
438 // ceil(time2). 478 // ceil(time2).
439 // 479 //
440 // However, time2 can be very large, so compute this carefully in the ca se where time2 480 // However, time2 can be very large, so compute this carefully in the ca se where time2
441 // exceeds the size of a size_t. 481 // exceeds the size of a size_t.
442 482
443 size_t fillToEndFrame = endFrame; 483 size_t fillToEndFrame = endFrame;
444 if (endFrame > time2 * sampleRate) 484 if (endFrame > time2 * sampleRate)
445 fillToEndFrame = static_cast<size_t>(ceil(time2 * sampleRate)); 485 fillToEndFrame = static_cast<size_t>(ceil(time2 * sampleRate));
446 486
447 ASSERT(fillToEndFrame >= startFrame); 487 ASSERT(fillToEndFrame >= startFrame);
448 size_t fillToFrame = fillToEndFrame - startFrame; 488 size_t fillToFrame = fillToEndFrame - startFrame;
449 fillToFrame = std::min(fillToFrame, static_cast<size_t>(numberOfValues)) ; 489 fillToFrame = std::min(fillToFrame, static_cast<size_t>(numberOfValues)) ;
450 490
451 ParamEvent::Type nextEventType = nextEvent ? static_cast<ParamEvent::Typ e>(nextEvent->getType()) : ParamEvent::LastType /* unknown */;
452
453 // First handle linear and exponential ramps which require looking ahead to the next event. 491 // First handle linear and exponential ramps which require looking ahead to the next event.
454 if (nextEventType == ParamEvent::LinearRampToValue) { 492 if (nextEventType == ParamEvent::LinearRampToValue) {
455 const float valueDelta = value2 - value1; 493 const float valueDelta = value2 - value1;
456 #if CPU(X86) || CPU(X86_64) 494 #if CPU(X86) || CPU(X86_64)
457 // Minimize in-loop operations. Calculate starting value and increme nt. Next step: value += inc. 495 // Minimize in-loop operations. Calculate starting value and increme nt. Next step: value += inc.
458 // value = value1 + (currentFrame/sampleRate - time1) * k * (value2 - value1); 496 // value = value1 + (currentFrame/sampleRate - time1) * k * (value2 - value1);
459 // inc = 4 / sampleRate * k * (value2 - value1); 497 // inc = 4 / sampleRate * k * (value2 - value1);
460 // Resolve recursion by expanding constants to achieve a 4-step loop unrolling. 498 // Resolve recursion by expanding constants to achieve a 4-step loop unrolling.
461 // value = value1 + ((currentFrame/sampleRate - time1) + i * sample FrameTimeIncr) * k * (value2 -value1), i in 0..3 499 // value = value1 + ((currentFrame/sampleRate - time1) + i * sample FrameTimeIncr) * k * (value2 -value1), i in 0..3
462 __m128 vValue = _mm_mul_ps(_mm_set_ps1(1 / sampleRate), _mm_set_ps(3 , 2, 1, 0)); 500 __m128 vValue = _mm_mul_ps(_mm_set_ps1(1 / sampleRate), _mm_set_ps(3 , 2, 1, 0));
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
529 567
530 for (; writeIndex < fillToFrame; ++writeIndex) { 568 for (; writeIndex < fillToFrame; ++writeIndex) {
531 values[writeIndex] = value; 569 values[writeIndex] = value;
532 value *= multiplier; 570 value *= multiplier;
533 ++currentFrame; 571 ++currentFrame;
534 } 572 }
535 // |value| got updated one extra time in the above loop. Restor e it to the last 573 // |value| got updated one extra time in the above loop. Restor e it to the last
536 // computed value. 574 // computed value.
537 if (writeIndex >= 1) 575 if (writeIndex >= 1)
538 value /= multiplier; 576 value /= multiplier;
577
578 // Due to roundoff it's possible that value exceeds value2. Cli p value to value2 if
579 // we are within 1/2 frame of time2.
580 if (currentFrame > time2 * sampleRate - 0.5)
581 value = value2;
539 } 582 }
540 } else { 583 } else {
541 // Handle event types not requiring looking ahead to the next event. 584 // Handle event types not requiring looking ahead to the next event.
542 switch (event.getType()) { 585 switch (event.getType()) {
543 case ParamEvent::SetValue: 586 case ParamEvent::SetValue:
544 case ParamEvent::LinearRampToValue: 587 case ParamEvent::LinearRampToValue:
545 { 588 {
546 currentFrame = fillToEndFrame; 589 currentFrame = fillToEndFrame;
547 590
548 // Simply stay at a constant value. 591 // Simply stay at a constant value.
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
815 for (; writeIndex < numberOfValues; ++writeIndex) 858 for (; writeIndex < numberOfValues; ++writeIndex)
816 values[writeIndex] = value; 859 values[writeIndex] = value;
817 860
818 // This value is used to set the .value attribute of the AudioParam. it sho uld be the last 861 // This value is used to set the .value attribute of the AudioParam. it sho uld be the last
819 // computed value. 862 // computed value.
820 return values[numberOfValues - 1]; 863 return values[numberOfValues - 1];
821 } 864 }
822 865
823 } // namespace blink 866 } // namespace blink
824 867
OLDNEW
« no previous file with comments | « third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698