Bug 1265401 - Perform linear interpolation when computing the SetValueCurveAtTime events; r?padenot draft
authorDan Minor <dminor@mozilla.com>
Mon, 24 Oct 2016 13:07:32 -0400
changeset 428923 fa0933650dee2b1b4f7bbd74cdfdb59c27bb4e73
parent 428476 215f9686117673a2c914ed207bc7da9bb8d741ad
child 534838 862c6fd142c6d3daa034cdbaabebd47b7cd9ea97
push id33420
push userdminor@mozilla.com
push dateMon, 24 Oct 2016 17:08:11 +0000
reviewerspadenot
bugs1265401
milestone52.0a1
Bug 1265401 - Perform linear interpolation when computing the SetValueCurveAtTime events; r?padenot MozReview-Commit-ID: IOiyq5a4P2A
dom/media/webaudio/AudioEventTimeline.cpp
dom/media/webaudio/test/test_audioParamSetCurveAtTime.html
dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html
--- a/dom/media/webaudio/AudioEventTimeline.cpp
+++ b/dom/media/webaudio/AudioEventTimeline.cpp
@@ -28,17 +28,25 @@ static float ExtractValueFromCurve(doubl
   if (t >= startTime + duration) {
     // After the duration, return the last curve value
     return aCurve[aCurveLength - 1];
   }
   double ratio = std::max((t - startTime) / duration, 0.0);
   if (ratio >= 1.0) {
     return aCurve[aCurveLength - 1];
   }
-  return aCurve[uint32_t(aCurveLength * ratio)];
+  uint32_t current = uint32_t(aCurveLength * ratio);
+  uint32_t next = current + 1;
+  if (next < aCurveLength) {
+    double t0 = double(current) / double(aCurveLength) * duration ;
+    double t1 = double(next) / double(aCurveLength) * duration ;
+    return LinearInterpolate(t0, aCurve[current], t1, aCurve[next], t - startTime);
+  } else {
+    return aCurve[current];
+  }
 }
 
 namespace mozilla {
 namespace dom {
 
 template <class ErrorResult> bool
 AudioEventTimeline::ValidateEvent(AudioTimelineEvent& aEvent,
                                   ErrorResult& aRv)
--- a/dom/media/webaudio/test/test_audioParamSetCurveAtTime.html
+++ b/dom/media/webaudio/test/test_audioParamSetCurveAtTime.html
@@ -11,42 +11,40 @@
 <script class="testbody" type="text/javascript">
 
 var T0 = 0;
 
 var gTest = {
   length: 2048,
   numberOfChannels: 1,
   createGraph: function(context) {
-    var sourceBuffer = context.createBuffer(1, 2048, context.sampleRate);
-    for (var i = 0; i < 2048; ++i) {
-      sourceBuffer.getChannelData(0)[i] = 1;
-    }
-
-    var source = context.createBufferSource();
-    source.buffer = sourceBuffer;
+    var source = context.createConstantSource();
 
     var gain = context.createGain();
     gain.gain.setValueCurveAtTime(this.curve, T0, this.duration);
-
     source.connect(gain);
 
     source.start(0);
     return gain;
   },
   createExpectedBuffers: function(context) {
     this.duration = 1024 / context.sampleRate;
-    this.curve = new Float32Array(100);
-    for (var i = 0; i < 100; ++i) {
-      this.curve[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
-    }
+    this.curve = new Float32Array([1.0, 0.5, 0.75, 0.25]);
     var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
+    var data = expectedBuffer.getChannelData(0);
     for (var i = 0; i < 2048; ++i) {
-      var t = i / context.sampleRate;
-      expectedBuffer.getChannelData(0)[i] = this.curve[Math.min(99, Math.floor(100 * Math.min(1.0, (t - T0) / this.duration)))];
+      if (i < 256) {
+        data[i] = 1.0 - 0.5*i/256;
+      } else if (i < 512) {
+        data[i] = 0.5 + 0.25*(i - 256)/256;
+      } else if (i < 768) {
+        data[i] = 0.75 - 0.5*(i - 512)/256;
+      } else {
+        data[i] = 0.25;
+      }
     }
     return expectedBuffer;
   },
 };
 
 runTest();
 
 </script>
--- a/dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html
+++ b/dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html
@@ -1,59 +1,67 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-  <title>Test AudioParam.linearRampToValue</title>
+  <title>Test AudioParam.setValueCurveAtTime twice</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="webaudio.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
+
+function linearInterpolate(t0, v0, t1, v1, t)
+{
+  return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));
+}
+
 var T0 = 0;
 
 var gTest = {
   length: 2048,
   numberOfChannels: 1,
   createGraph: function(context) {
-    var sourceBuffer = context.createBuffer(1, 2048, context.sampleRate);
-    for (var i = 0; i < 2048; ++i) {
-      sourceBuffer.getChannelData(0)[i] = 1;
-    }
-
     var curve2 = new Float32Array(100);
     for (var i = 0; i < 100; ++i) {
       curve2[i] = Math.sin(220 * 6 * Math.PI * i / context.sampleRate);
     }
 
-    var source = context.createBufferSource();
-    source.buffer = sourceBuffer;
+    var source = context.createConstantSource();
 
     var gain = context.createGain();
     gain.gain.setValueCurveAtTime(curve2, T0, this.duration/2);
-    //Set a diffrent curve from the first one
+    //Set a different curve from the first one
     gain.gain.setValueCurveAtTime(this.curve, T0, this.duration);
 
     source.connect(gain);
 
     source.start(0);
     return gain;
   },
   createExpectedBuffers: function(context) {
     this.duration = 1024 / context.sampleRate;
     this.curve = new Float32Array(100);
     for (var i = 0; i < 100; ++i) {
       this.curve[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
     }
     var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
     for (var i = 0; i < 2048; ++i) {
       var t = i / context.sampleRate;
-      expectedBuffer.getChannelData(0)[i] = this.curve[Math.min(99, Math.floor(100 * Math.min(1.0, (t - T0) / this.duration)))];
+      var current = Math.min(99, Math.floor(100 * Math.min(1.0, (t - T0) / this.duration)));
+      var next = current + 1;
+      if (next < this.curve.length) {
+        var t0 = current / this.curve.length * this.duration;
+        var t1 = next / this.curve.length * this.duration;
+        expectedBuffer.getChannelData(0)[i] = linearInterpolate(t0, this.curve[current], t1, this.curve[next], t);
+      } else {
+        expectedBuffer.getChannelData(0)[i] = this.curve[current];
+      }
     }
     return expectedBuffer;
   },
 };
 
 runTest();
 
 </script>