Bug 1265401 - Perform linear interpolation when computing the SetValueCurveAtTime events; r?padenot
MozReview-Commit-ID: IOiyq5a4P2A
--- 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>