Chromium Code Reviews| Index: third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-points.html |
| diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-points.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-points.html |
| index acfd67bda054543c17835610fa901334810bf559..8e3a8232c2d17cebf0d98d359f6d6ed7b8a51353 100644 |
| --- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-points.html |
| +++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-points.html |
| @@ -6,105 +6,149 @@ Tests that AudioBufferSourceNode supports loop-points with .loopStart and .loopE |
| <html> |
| <head> |
| +<script src="../../resources/testharness.js"></script> |
| +<script src="../../resources/testharnessreport.js"></script> |
| <script src="../resources/audit-util.js"></script> |
| -<script src="../resources/audio-testing.js"></script> |
| +<script src="../resources/audit.js"></script> |
| </head> |
| <body> |
| <script> |
| +let audit = Audit.createTaskRunner(); |
| -window.onload = init; |
| +let sampleRate = 44100.0; |
| +let numberOfNotes = 60; // play over a 5 octave range |
| +let noteDuration = 0.025; |
| +let noteSpacing = |
| + noteDuration + 0.005; // leave 5ms of silence between each "note" |
| +let lengthInSeconds = numberOfNotes * noteSpacing; |
| -var sampleRate = 44100.0; |
| -var numberOfNotes = 60; // play over a 5 octave range |
| -var noteDuration = 0.025; |
| -var noteSpacing = noteDuration + 0.005; // leave 5ms of silence between each "note" |
| -var lengthInSeconds = numberOfNotes * noteSpacing; |
| - |
| -var context = 0; |
| -var buffer = 0; |
| +let context = 0; |
| +let expectedAudio; |
| function createTestBuffer(frequency, sampleRate) { |
| - // Create a buffer containing two periods at this frequency. |
| - // The 1st half is a pure sine wave period scaled by a linear ramp from 0 -> 1. |
| - // The 2nd half of the buffer corresponds exactly to one pure sine wave period. |
| - var onePeriodDuration = 1 / frequency; |
| - var sampleFrameLength = 2 * onePeriodDuration * sampleRate; |
| + // Create a buffer containing two periods at this frequency. |
| + // The 1st half is a pure sine wave period scaled by a linear ramp from 0 -> |
| + // 1. The 2nd half of the buffer corresponds exactly to one pure sine wave |
| + // period. |
| + let onePeriodDuration = 1 / frequency; |
| + let sampleFrameLength = 2 * onePeriodDuration * sampleRate; |
| - var audioBuffer = context.createBuffer(1, sampleFrameLength, sampleRate); |
| + let audioBuffer = context.createBuffer(1, sampleFrameLength, sampleRate); |
| - var n = audioBuffer.length; |
| - var channelData = audioBuffer.getChannelData(0); |
| + let n = audioBuffer.length; |
| + let channelData = audioBuffer.getChannelData(0); |
| - for (var i = 0; i < n; ++i) { |
| - var sample = Math.sin(frequency * 2.0*Math.PI * i / sampleRate); |
| + for (let i = 0; i < n; ++i) { |
| + let sample = Math.sin(frequency * 2.0 * Math.PI * i / sampleRate); |
| - // Linear ramp from 0 -> 1 for the first period. |
| - // Stay at 1 for the 2nd period. |
| - var scale = i < n / 2 ? i / (n / 2) : 1; |
| - sample *= scale; |
| + // Linear ramp from 0 -> 1 for the first period. |
| + // Stay at 1 for the 2nd period. |
| + let scale = i < n / 2 ? i / (n / 2) : 1; |
| + sample *= scale; |
| - channelData[i] = sample; |
| - } |
| + channelData[i] = sample; |
| + } |
| - return audioBuffer; |
| + return audioBuffer; |
| } |
| -function playNote(time, duration, playbackRate) { |
| - var source = context.createBufferSource(); |
| - source.buffer = buffer; |
| - source.playbackRate.value = playbackRate; |
| - |
| - var gainNode = context.createGain(); |
| - source.connect(gainNode); |
| - gainNode.connect(context.destination); |
| - |
| - // Loop the 2nd half of the buffer. |
| - // We should be able to hear any problems as glitches if the looping incorrectly indexes to |
| - // anywhere outside of the desired loop-points, since only the 2nd half is a perfect sine-wave cycle, |
| - // while the 1st half of the buffer contains a linear ramp of a sine-wave cycle. |
| - source.loop = true; |
| - source.loopStart = 0.5 * buffer.duration; |
| - source.loopEnd = buffer.duration; |
| - |
| - // Play for the given duration. |
| - source.start(time); |
| - source.stop(time + duration); |
| - |
| - // Apply a quick linear fade-out to avoid a click at the end of the note. |
| - gainNode.gain.value = 1; |
| - gainNode.gain.setValueAtTime(1, time + duration - 0.005); |
| - gainNode.gain.linearRampToValueAtTime(0, time + duration); |
| +function playNote(buffer, time, duration, playbackRate) { |
| + let source = context.createBufferSource(); |
| + source.buffer = buffer; |
| + source.playbackRate.value = playbackRate; |
| + |
| + let gainNode = context.createGain(); |
| + source.connect(gainNode); |
| + gainNode.connect(context.destination); |
| + |
| + // Loop the 2nd half of the buffer. |
| + // We should be able to hear any problems as glitches if the looping |
| + // incorrectly indexes to anywhere outside of the desired loop-points, since |
| + // only the 2nd half is a perfect sine-wave cycle, while the 1st half of the |
| + // buffer contains a linear ramp of a sine-wave cycle. |
| + source.loop = true; |
| + source.loopStart = 0.5 * buffer.duration; |
| + source.loopEnd = buffer.duration; |
| + |
| + // Play for the given duration. |
| + source.start(time); |
| + source.stop(time + duration); |
| + |
| + // Apply a quick linear fade-out to avoid a click at the end of the note. |
| + gainNode.gain.value = 1; |
| + gainNode.gain.setValueAtTime(1, time + duration - 0.005); |
| + gainNode.gain.linearRampToValueAtTime(0, time + duration); |
| } |
| -function init() { |
| - if (!window.testRunner) |
| - return; |
| - |
| - // Create offline audio context. |
| - context = new OfflineAudioContext(2, sampleRate * lengthInSeconds, sampleRate); |
| - |
| - // Create the test buffer. |
| - // We'll loop this with the loop-points set for the 2nd half of this buffer. |
| - buffer = createTestBuffer(440.0, sampleRate); |
| - |
| - // Play all the notes as a chromatic scale. |
| - for (var i = 0; i < numberOfNotes; ++i) { |
| - var time = i * noteSpacing; |
| - var semitone = i - numberOfNotes/2; // start three octaves down |
| +audit.define( |
| + {label: 'initialize', description: 'Set up context and expected results'}, |
| + (task, should) => { |
| + // Create offline audio context. |
| + should( |
| + () => {context = new OfflineAudioContext( |
| + 2, sampleRate * lengthInSeconds, sampleRate)}, |
| + 'Creating context for testing') |
| + .notThrow(); |
|
hongchan
2017/03/03 16:01:34
I don't think we should assert on OAC here. This t
Raymond Toy
2017/03/03 17:40:50
This and below is my cheating way to get some usef
|
| + |
| + should( |
| + Audit.loadFileFromUrl('audiobuffersource-loop-points-expected.wav') |
|
hongchan
2017/03/03 16:01:34
This is about setting up the test. We don't have t
|
| + .then(arrayBuffer => { |
| + context.decodeAudioData(arrayBuffer).then(audioBuffer => { |
| + expectedAudio = audioBuffer; |
| + }); |
| + }), |
| + 'Fetching expected audio') |
| + .beResolved() |
| + .then(() => task.done()); |
| + }); |
| + |
| +audit.define( |
| + { |
| + label: 'test', |
| + description: 'Test loop points and compare with expected results' |
| + }, |
| + (task, should) => { |
| + // Create the test buffer. |
| + // We'll loop this with the loop-points set for the 2nd half of this |
| + // buffer. |
| + let buffer = createTestBuffer(440.0, sampleRate); |
| + |
| + // Play all the notes as a chromatic scale. |
| + for (let i = 0; i < numberOfNotes; ++i) { |
| + let time = i * noteSpacing; |
| + // start three octaves down |
| + let semitone = i - numberOfNotes / 2; |
| // Convert from semitone to rate. |
| - var playbackRate = Math.pow(2, semitone / 12); |
| - |
| - playNote(time, noteDuration, playbackRate); |
| - } |
| - |
| - context.oncomplete = finishAudioTest; |
| - context.startRendering(); |
| - |
| - testRunner.waitUntilDone(); |
| -} |
| + let playbackRate = Math.pow(2, semitone / 12); |
| + |
| + playNote(buffer, time, noteDuration, playbackRate); |
| + } |
| + |
| + context.startRendering() |
| + .then(renderedAudio => { |
| + // Compute a threshold based on the maximum error, |maxUlp|, in ULP. |
| + // This is experimentally determined. Assuming that the reference |
| + // file is a 16-bit wav file, the max values in the wave file |
| + // are +/- 32768. |
| + let maxUlp = 0.9999; |
| + let threshold = maxUlp / 32768; |
| + |
| + for (let k = 0; k < renderedAudio.numberOfChannels; ++k) { |
| + should( |
| + renderedAudio.getChannelData(k), |
| + 'Rendered audio for channel ' + k) |
| + .beCloseToArray( |
| + expectedAudio.getChannelData(k), |
| + {absoluteThreshold: threshold}); |
| + } |
| + }) |
| + .then(() => task.done()); |
| + }); |
| + |
| +audit.run(); |
| </script> |