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

Unified Diff: third_party/WebKit/LayoutTests/webaudio/Oscillator/start-sampling.html

Issue 2186813003: Sub-sample accurate start of OscillatorNode (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Adjust thresholds for Mac 10.11 (retina) Created 3 years, 11 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/LayoutTests/webaudio/Oscillator/start-sampling.html
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/start-sampling.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/start-sampling.html
new file mode 100644
index 0000000000000000000000000000000000000000..61032d0cf304b24e7666bee4117682ea1b0ea88c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/start-sampling.html
@@ -0,0 +1,173 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Test Sampling of Oscillator Start Times</title>
+ <script src="../../resources/testharness.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
+ <script src="../resources/audit-util.js"></script>
+ <script src="../resources/audit.js"></script>
+ </head>
+
+ <body>
+ <script>
+ // Experimentation indicates that this sample rate with a 440 Hz
+ // oscillator makes for a large difference in the difference signal if the
+ // oscillator start isn't sampled correctly.
+ let defaultSampleRate = 24000;
+ let renderDuration = 1;
+ let renderFrames = renderDuration * defaultSampleRate;
+
+ let audit = Audit.createTaskRunner();
+
+ audit.define("basic test small", function (task, should) {
+ task.describe("Start oscillator slightly past a sample frame")
+ testStartSampling(should, 1.25, {
+ error: 1.0842e-4,
+ snrThreshold: 84.054
+ })
+ .then(task.done.bind(task));
+ });
+
+ audit.define("basic test big", function (task, should) {
+ task.describe("Start oscillator slightly before a sample frame")
+ testStartSampling(should, 1.75, {
+ error: 1.0839e-4,
+ snrThreshold: 84.056
+ })
+ .then(task.done.bind(task));
+ });
+
+ audit.define("diff big offset", function (task, should) {
+ task.describe(
+ "Test sampling with start offset greater than 1/2 sampling frame"
+ );
+ // With a sample rate of 24000 Hz, and an oscillator frequency of 440 Hz
+ // (the default), a quarter wave delay is 13.636363... frames. This
+ // tests the case where the starting time is more than 1/2 frame from
+ // the preceding sampling frame. This tests one path of the internal
+ // implementation.
+ testStartWithGain(should, defaultSampleRate, {
+ error: 4.1724e-7,
+ snrThreshold: 137.536
+ })
+ .then(task.done.bind(task));
+ });
+
+ audit.define("diff small offset", function (task, should) {
+ task.describe(
+ "Test sampling with start offset less than 1/2 sampling frame");
+ // With a sample rate of 48000 Hz, and an oscillator frequency of 440 Hz
+ // (the default), a quarter wave delay is 27.2727... frames. This tests
+ // the case where the starting time is less than 1/2 frame from the
+ // preceding sampling frame. This tests one path of the internal
+ // implementation.
+ testStartWithGain(should, 48000, {
+ error: 4.1724e-7,
+ snrThreshold: 137.536
+ })
+ .then(task.done.bind(task));
+ });
+
+ function testStartSampling(should, startFrame, thresholds) {
+ // Start the oscillator in the middle of a sample frame and compare
+ // against the theoretical result.
+ let context = new OfflineAudioContext(1, renderFrames,
+ defaultSampleRate);
+ let osc = context.createOscillator();
+ osc.connect(context.destination);
+ osc.start(startFrame / context.sampleRate);
+
+ return context.startRendering().then(function (result) {
+ let actual = result.getChannelData(0);
+ let expected = new Array(actual.length);
+ expected.fill(0);
+
+ // The expected curve is
+ //
+ // sin(2*pi*f*(t-t0))
+ //
+ // where f is the oscillator frequency and t0 is the start time.
+ let actualStart = Math.ceil(startFrame);
+ let omega = 2 * Math.PI * osc.frequency.value / context.sampleRate;
+ for (let k = actualStart; k < actual.length; ++k) {
+ expected[k] = Math.sin(omega * (k - startFrame));
+ }
+
+ should(actual, "Oscillator.start(" + startFrame + " frames)")
+ .beCloseToArray(expected, {
+ absoluteThreshold: thresholds.error
+ });
+ let snr = 10 * Math.log10(computeSNR(actual, expected));
+ should(snr, "SNR (dB)")
+ .beGreaterThanOrEqualTo(thresholds.snrThreshold);
+ })
+ }
+
+ function testStartWithGain(should, sampleRate, thresholds) {
+ // Test consists of starting a cosine wave with a quarter wavelength
+ // delay and comparing that with a sine wave that has the initial
+ // quarter wavelength zeroed out. These should be equal.
+
+ let context = new OfflineAudioContext(3, renderFrames, sampleRate);
+ let osc = context.createOscillator();
+
+ let merger = context.createChannelMerger(3);
+ merger.connect(context.destination);
+
+ // Start the cosine oscillator at this time. This means the wave starts
+ // at frame 13.636363....
+ let quarterWaveTime = (1 / 4) / osc.frequency.value;
+
+ // Sine wave oscillator with gain term to zero out the initial quarter
+ // wave length of the output.
+ let g = context.createGain();
+ g.gain.setValueAtTime(0, 0);
+ g.gain.setValueAtTime(1, quarterWaveTime);
+ osc.connect(g);
+ g.connect(merger, 0, 2);
+ g.connect(merger, 0, 0);
+
+ // Cosine wave oscillator with starting after a quarter wave length.
+ let osc2 = context.createOscillator();
+ // Creates a cosine wave.
+ let wave = context.createPeriodicWave(
+ Float32Array.from([0, 1]),
+ Float32Array.from([0, 0]));
+ osc2.setPeriodicWave(wave);
+
+ osc2.connect(merger, 0, 1);
+
+ // A gain inverter so subtract the two waveforms.
+ let inverter = context.createGain();
+ inverter.gain.value = -1;
+ osc2.connect(inverter);
+ inverter.connect(merger, 0, 0);
+
+ osc.start();
+ osc2.start(quarterWaveTime);
+
+ return context.startRendering().then(function (result) {
+ // Channel 0 = diff
+ // Channel 1 = osc with start
+ // Channel 2 = osc with gain
+
+ // Channel 0 should be very close to 0.
+ // Channel 1 should match channel 2 very closely.
+ let diff = result.getChannelData(0);
+ let oscStart = result.getChannelData(1);
+ let oscGain = result.getChannelData(2);
+ let snr = 10 * Math.log10(computeSNR(oscStart, oscGain));
+
+ should(oscStart, "Delayed cosine oscillator at sample rate " + sampleRate)
+ .beCloseToArray(oscGain, {
+ absoluteThreshold: thresholds.error
+ });
+ should(snr, "SNR (dB)")
+ .beGreaterThanOrEqualTo(thresholds.snrThreshold);
+ });
+ }
+
+ audit.run();
+ </script>
+ </body>
+</html>
« no previous file with comments | « no previous file | third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698