| OLD | NEW |
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 <html> | 2 <html> |
| 3 <head> | 3 <head> |
| 4 <title>AudioBufferSourceNode - playbackRate test</title> | 4 <title>AudioBufferSourceNode - playbackRate test</title> |
| 5 <script src="../../resources/js-test.js"></script> | 5 <script src="../../resources/testharness.js"></script> |
| 6 <script src="../../resources/testharnessreport.js"></script> |
| 6 <script src="../resources/audit-util.js"></script> | 7 <script src="../resources/audit-util.js"></script> |
| 7 <script src="../resources/audio-testing.js"></script> | 8 <script src="../resources/audio-testing.js"></script> |
| 8 </head> | 9 </head> |
| 9 <body> | 10 <body> |
| 10 <script> | 11 <script> |
| 11 description("Test if AudioBufferSourceNode.playbackRate can playback at differ
ent rates properly."); | 12 let audit = Audit.createTaskRunner(); |
| 12 window.jsTestIsAsync = true; | |
| 13 | 13 |
| 14 // Any sample rate mutiple of 128 is valid for this test, but here it uses | 14 // Any sample rate mutiple of 128 is valid for this test, but here it uses |
| 15 // 48000Hz because it is a commonly used number that happens to be multiple | 15 // 48000Hz because it is a commonly used number that happens to be multiple |
| 16 // of 128. | 16 // of 128. |
| 17 var sampleRate = 48000; | 17 let sampleRate = 48000; |
| 18 | 18 |
| 19 // The test iterates over 60 pitches starting from 36. (MIDI pitch of C2) | 19 // The test iterates over 60 pitches starting from 36. (MIDI pitch of C2) |
| 20 var fundamentalPitch = 36; | 20 let fundamentalPitch = 36; |
| 21 var numberOfPitches = 60; | 21 let numberOfPitches = 60; |
| 22 | 22 |
| 23 var noteDuration = 0.025; | 23 let noteDuration = 0.025; |
| 24 var totalDuration = noteDuration * numberOfPitches; | 24 let totalDuration = noteDuration * numberOfPitches; |
| 25 | 25 |
| 26 // Test constraints for each octave. | 26 // Test constraints for each octave. |
| 27 var testConstraints = [{ | 27 let testConstraints = [{ |
| 28 thresholdSNR: 103.8508, | 28 thresholdSNR: 103.8508, |
| 29 thresholdDiffULP: 0.3028 | 29 thresholdDiffULP: 0.3028 |
| 30 }, { | 30 }, { |
| 31 thresholdSNR: 103.8657, | 31 thresholdSNR: 103.8657, |
| 32 thresholdDiffULP: 0.3029 | 32 thresholdDiffULP: 0.3029 |
| 33 }, { | 33 }, { |
| 34 thresholdSNR: 103.8141, | 34 thresholdSNR: 103.8141, |
| 35 thresholdDiffULP: 0.3047 | 35 thresholdDiffULP: 0.3047 |
| 36 }, { | 36 }, { |
| 37 thresholdSNR: 103.6818, | 37 thresholdSNR: 103.6818, |
| 38 thresholdDiffULP: 0.3262 | 38 thresholdDiffULP: 0.3262 |
| 39 }, { | 39 }, { |
| 40 thresholdSNR: 103.1514, | 40 thresholdSNR: 103.1514, |
| 41 thresholdDiffULP: 0.3946 | 41 thresholdDiffULP: 0.3946 |
| 42 }]; | 42 }]; |
| 43 | 43 |
| 44 function pitchToFrequency(midiPitch) { | 44 function pitchToFrequency(midiPitch) { |
| 45 return 440 * Math.pow(2, (Math.floor(midiPitch) - 69) / 12); | 45 return 440 * Math.pow(2, (Math.floor(midiPitch) - 69) / 12); |
| 46 } | 46 } |
| 47 | 47 |
| 48 function pitchDiffToPlaybackRate(midiPitchDiff) { | 48 function pitchDiffToPlaybackRate(midiPitchDiff) { |
| 49 return Math.pow(2, midiPitchDiff / 12); | 49 return Math.pow(2, midiPitchDiff / 12); |
| 50 } | 50 } |
| 51 | 51 |
| 52 function createSineWaveBuffer(context, frequency, duration) { | 52 function createSineWaveBuffer(context, frequency, duration) { |
| 53 var buffer = context.createBuffer(1, duration * sampleRate, sampleRate); | 53 let buffer = context.createBuffer(1, duration * sampleRate, sampleRate); |
| 54 var data = buffer.getChannelData(0); | 54 let data = buffer.getChannelData(0); |
| 55 var omega = 2 * Math.PI * frequency / sampleRate; | 55 let omega = 2 * Math.PI * frequency / sampleRate; |
| 56 for (var i = 0; i < data.length; i++) | 56 for (let i = 0; i < data.length; i++) |
| 57 data[i] = Math.sin(omega * i); | 57 data[i] = Math.sin(omega * i); |
| 58 | 58 |
| 59 return buffer; | 59 return buffer; |
| 60 } | 60 } |
| 61 | 61 |
| 62 var context = new OfflineAudioContext(2, totalDuration * sampleRate, sampleRat
e); | 62 // This is the fundamental buffer for playbackRate modulation. The duration |
| 63 | 63 // of this buffer is arbitrary but long enough to produce the sound without |
| 64 // This is the fundamental buffer for playbackRate modulation. The duration of | |
| 65 // this buffer is arbitrary but long enough to produce the sound without | |
| 66 // running short. | 64 // running short. |
| 67 var fundamentalBuffer = createSineWaveBuffer(context, pitchToFrequency(fundame
ntalPitch), totalDuration); | 65 let fundamentalBuffer; |
| 68 | 66 |
| 69 // A unit test consists of 2 sources: the 'actual' source runs a buffer with | 67 // A unit test consists of 2 sources: the 'actual' source runs a buffer with |
| 70 // the playback rate modulated and the 'expected' source runs a mathmatically | 68 // the playback rate modulated and the 'expected' source runs a |
| 71 // generated sound buffer. | 69 // mathmatically generated sound buffer. |
| 72 function runUnitTest(context, noteStart, notePitch) { | 70 function runUnitTest(context, noteStart, notePitch) { |
| 73 var actualSrc = context.createBufferSource(); | 71 let actualSrc = context.createBufferSource(); |
| 74 var expectedSrc = context.createBufferSource(); | 72 let expectedSrc = context.createBufferSource(); |
| 75 var merger = context.createChannelMerger(2); | 73 let merger = context.createChannelMerger(2); |
| 76 | 74 |
| 77 actualSrc.buffer = fundamentalBuffer; | 75 actualSrc.buffer = fundamentalBuffer; |
| 78 expectedSrc.buffer = createSineWaveBuffer(context, pitchToFrequency(notePitc
h), noteDuration); | 76 expectedSrc.buffer = createSineWaveBuffer(context, |
| 79 actualSrc.playbackRate.value = pitchDiffToPlaybackRate(notePitch - fundament
alPitch); | 77 pitchToFrequency(notePitch), noteDuration); |
| 78 actualSrc.playbackRate.value = |
| 79 pitchDiffToPlaybackRate(notePitch - fundamentalPitch); |
| 80 | 80 |
| 81 actualSrc.connect(merger, 0, 0); | 81 actualSrc.connect(merger, 0, 0); |
| 82 expectedSrc.connect(merger, 0, 1); | 82 expectedSrc.connect(merger, 0, 1); |
| 83 merger.connect(context.destination); | 83 merger.connect(context.destination); |
| 84 | 84 |
| 85 actualSrc.start(noteStart); | 85 actualSrc.start(noteStart); |
| 86 actualSrc.stop(noteStart + noteDuration); | 86 actualSrc.stop(noteStart + noteDuration); |
| 87 expectedSrc.start(noteStart); | 87 expectedSrc.start(noteStart); |
| 88 expectedSrc.stop(noteStart + noteDuration); | 88 expectedSrc.stop(noteStart + noteDuration); |
| 89 } | 89 } |
| 90 | 90 |
| 91 // Schedule tests up to 60 pitches above from the fundamental pitch. | |
| 92 for (var iteration = 0; iteration < numberOfPitches; iteration++) | |
| 93 runUnitTest(context, noteDuration * iteration, fundamentalPitch + iteration)
; | |
| 94 | 91 |
| 95 // Once the rendering is complete, split the buffer into 5 octaves. Then | 92 // Test if AudioBufferSourceNode.playbackRate can playback at different rates |
| 96 // perform the SNR and the maximum difference ULP check for each octave with | 93 // properly. |
| 97 // different constraints. | 94 audit.defineTask("playbackrate-test", function (taskDone) { |
| 98 context.startRendering().then(function (renderedBuffer) { | 95 let context = new OfflineAudioContext(2, totalDuration * |
| 99 var actual = renderedBuffer.getChannelData(0); | 96 sampleRate, |
| 100 var expected = renderedBuffer.getChannelData(1); | 97 sampleRate); |
| 101 var octaveLength = Math.floor(noteDuration * 12 * sampleRate); | 98 fundamentalBuffer = createSineWaveBuffer(context, |
| 99 pitchToFrequency(fundamentalPitch), totalDuration); |
| 102 | 100 |
| 103 for (var i = 0; i < numberOfPitches / 12; i++) { | 101 // Schedule tests up to 60 pitches above from the fundamental pitch. |
| 104 var start = i * octaveLength, end = (i + 1) * octaveLength; | 102 for (let iteration = 0; iteration < numberOfPitches; iteration++) |
| 105 var octaveActual = actual.subarray(start, end); | 103 runUnitTest(context, noteDuration * iteration, fundamentalPitch + |
| 106 var octaveExpected = expected.subarray(start, end); | 104 iteration); |
| 107 | 105 |
| 108 compareBuffersWithConstraints(octaveActual, octaveExpected, testConstraint
s[i]); | 106 // Once the rendering is complete, split the buffer into 5 octaves. Then |
| 109 } | 107 // perform the SNR and the maximum difference ULP check for each octave |
| 108 // with different constraints. |
| 109 context.startRendering() |
| 110 .then(function (renderedBuffer) { |
| 111 let actual = renderedBuffer.getChannelData(0); |
| 112 let expected = renderedBuffer.getChannelData(1); |
| 113 let octaveLength = Math.floor(noteDuration * 12 * sampleRate); |
| 110 | 114 |
| 111 finishJSTest(); | 115 for (let i = 0; i < numberOfPitches / 12; i++) { |
| 116 let start = i * octaveLength; |
| 117 let end = (i + 1) * octaveLength; |
| 118 let octaveActual = actual.subarray(start, end); |
| 119 let octaveExpected = expected.subarray(start, end); |
| 120 |
| 121 compareBuffersWithConstraints(octaveActual, octaveExpected, |
| 122 testConstraints[i]); |
| 123 } |
| 124 |
| 125 }) |
| 126 .then(taskDone); |
| 112 }); | 127 }); |
| 113 | 128 |
| 114 successfullyParsed = true; | 129 audit.runTasks(); |
| 115 </script> | 130 </script> |
| 116 </body> | 131 </body> |
| 117 </html> | 132 </html> |
| OLD | NEW |