OLD | NEW |
1 <!doctype html> | 1 <!DOCTYPE html> |
2 <html> | 2 <html> |
3 <head> | 3 <head> |
| 4 <title> |
| 5 Test Analyser.getByteTimeDomainData() |
| 6 </title> |
4 <script src="../../resources/testharness.js"></script> | 7 <script src="../../resources/testharness.js"></script> |
5 <script src="../../resources/testharnessreport.js"></script> | 8 <script src="../../resources/testharnessreport.js"></script> |
6 <script src="../resources/audit-util.js"></script> | 9 <script src="../resources/audit-util.js"></script> |
7 <script src="../resources/audit.js"></script> | 10 <script src="../resources/audit.js"></script> |
8 <title>Test Analyser.getByteTimeDomainData()</title> | |
9 </head> | 11 </head> |
| 12 <body> |
| 13 <script id="layout-test-code"> |
| 14 let sampleRate = 48000; |
| 15 // The size of the analyser frame. Anything larger than 128 is ok, but |
| 16 // should be long enough to capture the peaks of the oscillator waveform. |
| 17 let fftSize = 256; |
| 18 // Number of frames to render. Should be greater than the fftSize, but is |
| 19 // otherwise arbitrary. |
| 20 let renderFrames = 2 * fftSize; |
10 | 21 |
11 <body> | 22 let audit = Audit.createTaskRunner(); |
12 <script> | |
13 var sampleRate = 48000; | |
14 // The size of the analyser frame. Anything larger than 128 is ok, but sh
ould be long enough | |
15 // to capture the peaks of the oscillator waveform. | |
16 var fftSize = 256; | |
17 // Number of frames to render. Should be greater than the fftSize, but is
otherwise | |
18 // arbitrary. | |
19 var renderFrames = 2 * fftSize; | |
20 | 23 |
21 var audit = Audit.createTaskRunner(); | 24 // Test that getByteTimeDomainData returns the correct values. This test |
| 25 // depends on getFloatTimeDomainData returning the correct data (for which |
| 26 // there is already a test). |
| 27 audit.define('byte-data', (task, should) => { |
| 28 let context = new OfflineAudioContext(1, renderFrames, sampleRate); |
22 | 29 |
23 // Test that getByteTimeDomainData returns the correct values. This test
depends on | 30 // Create a sawtooth as the signal under test. A sine wave or triangle |
24 // getFloatTimeDomainData returning the correct data (for which there is a
lready a test). | 31 // wave would probably also work. |
25 audit.define("byte-data", (task, should) => { | 32 let src = context.createOscillator(); |
26 var context = new OfflineAudioContext(1, renderFrames, sampleRate); | 33 src.type = 'sawtooth'; |
27 | 34 // Choose a frequency high enough that we get at least a full period in |
28 // Create a sawtooth as the signal under test. A sine wave or triangle
wave would probably | 35 // one analyser fftSize frame. Otherwise, the frequency is arbitrary. |
29 // also work. | |
30 var src = context.createOscillator(); | |
31 src.type = "sawtooth"; | |
32 // Choose a frequency high enough that we get at least a full period in
one analyser fftSize | |
33 // frame. Otherwise, the frequency is arbitrary. | |
34 src.frequency.value = 440; | 36 src.frequency.value = 440; |
35 | 37 |
36 // Gain node to make sure the signal goes somewhat above 1, for testing
clipping. | 38 // Gain node to make sure the signal goes somewhat above 1, for testing |
37 var gain = context.createGain(); | 39 // clipping. |
| 40 let gain = context.createGain(); |
38 gain.gain.value = 1.5; | 41 gain.gain.value = 1.5; |
39 | 42 |
40 // The analyser node to test | 43 // The analyser node to test |
41 var analyser = context.createAnalyser(); | 44 let analyser = context.createAnalyser(); |
42 analyser.fftSize = fftSize; | 45 analyser.fftSize = fftSize; |
43 | 46 |
44 // Connect the graph. | 47 // Connect the graph. |
45 src.connect(gain); | 48 src.connect(gain); |
46 gain.connect(analyser); | 49 gain.connect(analyser); |
47 analyser.connect(context.destination); | 50 analyser.connect(context.destination); |
48 | 51 |
49 // Stop rendering after one analyser frame so we can grab the data. | 52 // Stop rendering after one analyser frame so we can grab the data. |
50 context.suspend(fftSize / sampleRate).then(function () { | 53 context.suspend(fftSize / sampleRate) |
51 var floatData = new Float32Array(fftSize); | 54 .then(function() { |
52 var byteData = new Uint8Array(fftSize); | 55 let floatData = new Float32Array(fftSize); |
| 56 let byteData = new Uint8Array(fftSize); |
53 | 57 |
54 analyser.getFloatTimeDomainData(floatData); | 58 analyser.getFloatTimeDomainData(floatData); |
55 analyser.getByteTimeDomainData(byteData); | 59 analyser.getByteTimeDomainData(byteData); |
56 | 60 |
57 // Use the float data to compute the expected value for the byte data. | 61 // Use the float data to compute the expected value for the byte |
58 var expected = new Float32Array(fftSize); | 62 // data. |
59 for (var k = 0; k < fftSize; ++k) { | 63 let expected = new Float32Array(fftSize); |
60 // It's important to do Math.fround to match the single-precision fl
oat in the | 64 for (let k = 0; k < fftSize; ++k) { |
61 // implementation! | 65 // It's important to do Math.fround to match the |
62 var value = Math.fround(128 * Math.fround(1 + floatData[k])); | 66 // single-precision float in the implementation! |
63 // Clip the result to lie in the range [0, 255]. | 67 let value = Math.fround(128 * Math.fround(1 + floatData[k])); |
64 expected[k] = Math.floor(Math.min(255, Math.max(0, value))); | 68 // Clip the result to lie in the range [0, 255]. |
65 } | 69 expected[k] = Math.floor(Math.min(255, Math.max(0, value))); |
| 70 } |
66 | 71 |
67 // Find the first index of the first sample that exceeds +1 or -1. Th
e test MUST have at | 72 // Find the first index of the first sample that exceeds +1 or -1. |
68 // least one such value. | 73 // The test MUST have at least one such value. |
69 var indexMax = floatData.findIndex(function (x) { return x > 1; }); | 74 let indexMax = floatData.findIndex(function(x) { |
70 var indexMin = floatData.findIndex(function (x) { return x < -1; }); | 75 return x > 1; |
71 | 76 }); |
72 should(indexMax, "Index of first sample greater than +1").beGreaterTha
nOrEqualTo(0); | 77 let indexMin = floatData.findIndex(function(x) { |
73 should(indexMin, "Index of first sample less than -1").beGreaterThanOr
EqualTo(0); | 78 return x < -1; |
| 79 }); |
74 | 80 |
75 // Verify explicitly that clipping happened correctly at the above ind
ices. | 81 should(indexMax, 'Index of first sample greater than +1') |
76 should( | 82 .beGreaterThanOrEqualTo(0); |
77 byteData[indexMax], | 83 should(indexMin, 'Index of first sample less than -1') |
78 "Clip " + floatData[indexMax].toPrecision(6) + ": byteData[" + | 84 .beGreaterThanOrEqualTo(0); |
79 indexMax + "]").beEqualTo(255); | |
80 should( | |
81 byteData[indexMin], | |
82 "Clip " + floatData[indexMin].toPrecision(6) + ": byteData[" + | |
83 indexMin + "]").beEqualTo(0); | |
84 | 85 |
85 // Verify that all other samples are computed correctly. | 86 // Verify explicitly that clipping happened correctly at the above |
86 should(byteData, "Byte data").beEqualToArray(expected); | 87 // indices. |
87 }).then(context.resume.bind(context)) | 88 should( |
| 89 byteData[indexMax], |
| 90 'Clip ' + floatData[indexMax].toPrecision(6) + |
| 91 ': byteData[' + indexMax + ']') |
| 92 .beEqualTo(255); |
| 93 should( |
| 94 byteData[indexMin], |
| 95 'Clip ' + floatData[indexMin].toPrecision(6) + ': byteData[' + |
| 96 indexMin + ']') |
| 97 .beEqualTo(0); |
| 98 |
| 99 // Verify that all other samples are computed correctly. |
| 100 should(byteData, 'Byte data').beEqualToArray(expected); |
| 101 }) |
| 102 .then(context.resume.bind(context)) |
88 | 103 |
89 src.start(); | 104 src.start(); |
90 context.startRendering().then(() => task.done()); | 105 context.startRendering().then(() => task.done()); |
91 }); | 106 }); |
92 | 107 |
93 audit.run(); | 108 audit.run(); |
94 </script> | 109 </script> |
95 </body> | 110 </body> |
96 </html> | 111 </html> |
OLD | NEW |