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 |