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