Bug 1265401 - Perform linear interpolation when computing the SetValueCurveAtTime events; r=padenot
authorDan Minor <dminor@mozilla.com>
Mon, 24 Oct 2016 13:07:32 -0400
changeset 319319 64293caeec1e6474b6b7c63988f8207164d7d5c2
parent 319318 7854c40a579705adb28c70eb2f5466d0e8e02a32
child 319320 4cd27ee0834fdc646d0d4ee789efe9fc0e547264
push id30869
push userphilringnalda@gmail.com
push dateWed, 26 Oct 2016 04:57:48 +0000
treeherdermozilla-central@9471b3c49b2c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1265401
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
@@ -32,17 +32,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>