| OLD | NEW |
| 1 <!doctype html> | 1 <!doctype html> |
| 2 <html> | 2 <html> |
| 3 <head> | 3 <head> |
| 4 <script src="../../resources/testharness.js"></script> | 4 <script src="../../resources/testharness.js"></script> |
| 5 <script src="../../resources/testharnessreport.js"></script> | 5 <script src="../../resources/testharnessreport.js"></script> |
| 6 <script src="../resources/audit-util.js"></script> | 6 <script src="../resources/audit-util.js"></script> |
| 7 <script src="../resources/audio-testing.js"></script> | 7 <script src="../resources/audit.js"></script> |
| 8 <title>Test AnalyserNode getFloatTimeDomainData</title> | 8 <title>Test AnalyserNode getFloatTimeDomainData</title> |
| 9 </head> | 9 </head> |
| 10 | 10 |
| 11 <body> | 11 <body> |
| 12 <script> | 12 <script> |
| 13 // Use a power of two to eliminate any round-off in the computation of the
times for | 13 // Use a power of two to eliminate any round-off in the computation of the
times for |
| 14 // context.suspend(). | 14 // context.suspend(). |
| 15 var sampleRate = 32768; | 15 var sampleRate = 32768; |
| 16 | 16 |
| 17 // The largest FFT size for the analyser node is 32768. We want to render
longer than this so | 17 // The largest FFT size for the analyser node is 32768. We want to render
longer than this so |
| 18 // that we have at least one complete buffer of data of 32768 samples. | 18 // that we have at least one complete buffer of data of 32768 samples. |
| 19 var renderFrames = 2 * 32768; | 19 var renderFrames = 2 * 32768; |
| 20 var renderDuration = renderFrames / sampleRate; | 20 var renderDuration = renderFrames / sampleRate; |
| 21 | 21 |
| 22 var audit = Audit.createTaskRunner(); | 22 var audit = Audit.createTaskRunner(); |
| 23 | 23 |
| 24 // Test that getFloatTimeDomainData handles short and long vectors correct
ly. | 24 // Test that getFloatTimeDomainData handles short and long vectors correct
ly. |
| 25 audit.defineTask("short and long vector", function (done) { | 25 audit.define("short and long vector", (task, should) => { |
| 26 var fftSize = 32; | 26 var fftSize = 32; |
| 27 var graphInfo = createGraph(fftSize); | 27 var graphInfo = createGraph(fftSize); |
| 28 var context = graphInfo.context; | 28 var context = graphInfo.context; |
| 29 var analyser = graphInfo.analyser; | 29 var analyser = graphInfo.analyser; |
| 30 var signalBuffer = graphInfo.signalBuffer; | 30 var signalBuffer = graphInfo.signalBuffer; |
| 31 var signal = signalBuffer.getChannelData(0); | 31 var signal = signalBuffer.getChannelData(0); |
| 32 | 32 |
| 33 var success = true; | 33 var success = true; |
| 34 var sampleFrame = 128; | 34 var sampleFrame = 128; |
| 35 | 35 |
| 36 context.suspend(sampleFrame / sampleRate).then(function () { | 36 context.suspend(sampleFrame / sampleRate).then(function () { |
| 37 var shortData = new Float32Array(8); | 37 var shortData = new Float32Array(8); |
| 38 // Initialize the array to Infinity to represent uninitialize data. | 38 // Initialize the array to Infinity to represent uninitialize data. |
| 39 shortData.fill(Infinity); | 39 shortData.fill(Infinity); |
| 40 | 40 |
| 41 analyser.getFloatTimeDomainData(shortData); | 41 analyser.getFloatTimeDomainData(shortData); |
| 42 | 42 |
| 43 // The short array should be filled with the expected data, with no er
rors thrown. | 43 // The short array should be filled with the expected data, with no er
rors thrown. |
| 44 | 44 |
| 45 var expected = signal.subarray(sampleFrame - fftSize, sampleFrame); | 45 var expected = signal.subarray(sampleFrame - fftSize, sampleFrame); |
| 46 success = Should(shortData.length + "-element time domain data", short
Data) | 46 should(shortData, shortData.length + "-element time domain data") |
| 47 .beEqualToArray(expected.subarray(0, shortData.length)) && success; | 47 .beEqualToArray(expected.subarray(0, shortData.length)); |
| 48 | 48 |
| 49 var longData = new Float32Array(2 * fftSize); | 49 var longData = new Float32Array(2 * fftSize); |
| 50 // Initialize the array to Infinity to represent uninitialize data. | 50 // Initialize the array to Infinity to represent uninitialize data. |
| 51 longData.fill(Infinity); | 51 longData.fill(Infinity); |
| 52 | 52 |
| 53 analyser.getFloatTimeDomainData(longData); | 53 analyser.getFloatTimeDomainData(longData); |
| 54 | 54 |
| 55 // The long array should filled with the expected data but the extra e
lements should be | 55 // The long array should filled with the expected data but the extra e
lements should be |
| 56 // untouched. | 56 // untouched. |
| 57 success = Should("longData.subarray(0, " + fftSize + ")", | 57 should(longData.subarray(0, fftSize), "longData.subarray(0, " + fftSiz
e + ")") |
| 58 longData.subarray(0, fftSize), { | 58 .beEqualToArray(expected); |
| 59 numberOfArrayLog: 32 | |
| 60 }) | |
| 61 .beEqualToArray(expected) && success; | |
| 62 | 59 |
| 63 success = Should("Unfilled elements longData.subarray(" + fftSize + ")
", | 60 should(longData.subarray(fftSize), "Unfilled elements longData.subarra
y(" + fftSize + ")") |
| 64 longData.subarray(fftSize)) | 61 .beConstantValueOf(Infinity); |
| 65 .beConstantValueOf(Infinity) && success; | |
| 66 }).then(context.resume.bind(context)); | 62 }).then(context.resume.bind(context)); |
| 67 | 63 |
| 68 context.startRendering().then(function (buffer) { | 64 context.startRendering().then(() => task.done()); |
| 69 Should("Long and short time domain arrays handled", success) | |
| 70 .summarize("correctly.", "incorrectly."); | |
| 71 }).then(done); | |
| 72 }); | 65 }); |
| 73 | 66 |
| 74 var success = true; | 67 var success = true; |
| 75 | 68 |
| 76 // Generate tests for all valid FFT sizes for an AnalyserNode. | 69 // Generate tests for all valid FFT sizes for an AnalyserNode. |
| 77 for (var k = 5; k < 16; ++k) { | 70 for (var k = 5; k < 16; ++k) { |
| 78 var fftSize = Math.pow(2, k); | 71 var fftSize = Math.pow(2, k); |
| 79 (function (n) { | 72 (function (n) { |
| 80 // We grab a sample at (roughly) half the rendering duration. | 73 // We grab a sample at (roughly) half the rendering duration. |
| 81 audit.defineTask("fftSize " + n, function (done) { | 74 audit.define("fftSize " + n, (task, should) => { |
| 82 runTest(n, renderDuration / 2).then(done); | 75 runTest(n, renderDuration / 2, should).then(() => task.done()); |
| 83 }); | 76 }); |
| 84 })(fftSize); | 77 })(fftSize); |
| 85 } | 78 } |
| 86 | 79 |
| 87 audit.defineTask("summarize size tests", function (done) { | |
| 88 Should("Time domain data", success) | |
| 89 .summarize("contained the correct data for each size.", | |
| 90 "did not contain the correct data for each size."); | |
| 91 | |
| 92 done(); | |
| 93 }); | |
| 94 | |
| 95 // Special case for a large size, but the sampling point is early. The in
itial part of the | 80 // Special case for a large size, but the sampling point is early. The in
itial part of the |
| 96 // buffer should be filled with zeroes. | 81 // buffer should be filled with zeroes. |
| 97 | 82 |
| 98 audit.defineTask("initial zeroes", function (done) { | 83 audit.define("initial zeroes", (task, should) => { |
| 99 // Somewhat arbitrary size for the analyser. It should be greater than
one rendering | 84 // Somewhat arbitrary size for the analyser. It should be greater than
one rendering |
| 100 // quantum. | 85 // quantum. |
| 101 var fftSize = 2048; | 86 var fftSize = 2048; |
| 102 var graphInfo = createGraph(fftSize); | 87 var graphInfo = createGraph(fftSize); |
| 103 var context = graphInfo.context; | 88 var context = graphInfo.context; |
| 104 var analyser = graphInfo.analyser; | 89 var analyser = graphInfo.analyser; |
| 105 var signalBuffer = graphInfo.signalBuffer; | 90 var signalBuffer = graphInfo.signalBuffer; |
| 106 | 91 |
| 107 var data = new Float32Array(fftSize); | 92 var data = new Float32Array(fftSize); |
| 108 | 93 |
| 109 success = true; | 94 success = true; |
| 110 // Suspend every rendering quantum and examine the analyser data. | 95 // Suspend every rendering quantum and examine the analyser data. |
| 111 for (var k = 128; k <= fftSize; k += 128) { | 96 for (var k = 128; k <= fftSize; k += 128) { |
| 112 context.suspend(k / sampleRate).then(function () { | 97 context.suspend(k / sampleRate).then(function () { |
| 113 analyser.getFloatTimeDomainData(data); | 98 analyser.getFloatTimeDomainData(data); |
| 114 var sampleFrame = context.currentTime * sampleRate; | 99 var sampleFrame = context.currentTime * sampleRate; |
| 115 | 100 |
| 116 // Verify that the last k frames are not zero, but the first fftSize
- k frames are. | 101 // Verify that the last k frames are not zero, but the first fftSize
- k frames are. |
| 117 var prefix = "At frame " + (sampleFrame - 1) + ": data.subarray"; | 102 var prefix = "At frame " + (sampleFrame - 1) + ": data.subarray"; |
| 118 if (sampleFrame < fftSize) { | 103 if (sampleFrame < fftSize) { |
| 119 success = Should(prefix + "(0, " + (fftSize - sampleFrame) + ")", | 104 should(data.subarray(0, fftSize - sampleFrame), |
| 120 data.subarray(0, fftSize - sampleFrame)) | 105 prefix + "(0, " + (fftSize - sampleFrame) + ")") |
| 121 .beConstantValueOf(0) && success; | 106 .beConstantValueOf(0) && success; |
| 122 } | 107 } |
| 123 | 108 |
| 124 var signal = signalBuffer.getChannelData(0); | 109 var signal = signalBuffer.getChannelData(0); |
| 125 success = Should(prefix + "(" + (fftSize - sampleFrame) + ", " + fft
Size + ")", | 110 should(data.subarray(fftSize - sampleFrame, fftSize), |
| 126 data.subarray(fftSize - sampleFrame, fftSize)) | 111 prefix + "(" + (fftSize - sampleFrame) + ", " + fftSize + ")") |
| 127 .beEqualToArray(signal.subarray(0, sampleFrame)) && success; | 112 .beEqualToArray(signal.subarray(0, sampleFrame)) && success; |
| 128 }).then(context.resume.bind(context)); | 113 }).then(context.resume.bind(context)); |
| 129 } | 114 } |
| 130 | 115 |
| 131 context.startRendering().then(function (b) { | 116 context.startRendering().then(() => task.done()); |
| 132 Should("Time domain data", success) | |
| 133 .summarize( | |
| 134 "contained initial zeroes and correct data as expected", | |
| 135 "did not contain initial zeroes and correct data as expected."); | |
| 136 }).then(done); | |
| 137 }); | 117 }); |
| 138 | 118 |
| 139 audit.defineTask("finish", function (done) { | 119 audit.run(); |
| 140 done(); | |
| 141 }); | |
| 142 | |
| 143 audit.runTasks(); | |
| 144 | 120 |
| 145 // Run test of an AnalyserNode with fftSize of |fftSize|, and with the dat
a from the node | 121 // Run test of an AnalyserNode with fftSize of |fftSize|, and with the dat
a from the node |
| 146 // being requested at time |sampletime|. The result from the analyser nod
e is compared | 122 // being requested at time |sampletime|. The result from the analyser nod
e is compared |
| 147 // against the expected data. The result of startRendering() is returned. | 123 // against the expected data. The result of startRendering() is returned. |
| 148 function runTest(fftSize, sampleTime) { | 124 function runTest(fftSize, sampleTime, should) { |
| 149 var graphInfo = createGraph(fftSize); | 125 var graphInfo = createGraph(fftSize); |
| 150 var context = graphInfo.context; | 126 var context = graphInfo.context; |
| 151 var analyser = graphInfo.analyser; | 127 var analyser = graphInfo.analyser; |
| 152 var signalBuffer = graphInfo.signalBuffer; | 128 var signalBuffer = graphInfo.signalBuffer; |
| 153 | 129 |
| 154 // Grab the data at the requested time. | 130 // Grab the data at the requested time. |
| 155 context.suspend(sampleTime).then(function () { | 131 context.suspend(sampleTime).then(function () { |
| 156 var lastFrame = Math.floor(context.currentTime * sampleRate); | 132 var lastFrame = Math.floor(context.currentTime * sampleRate); |
| 157 | 133 |
| 158 // Grab the time domain data from the analyzer and compare against the
expected result. | 134 // Grab the time domain data from the analyzer and compare against the
expected result. |
| 159 var actualFloatData = new Float32Array(fftSize); | 135 var actualFloatData = new Float32Array(fftSize); |
| 160 analyser.getFloatTimeDomainData(actualFloatData); | 136 analyser.getFloatTimeDomainData(actualFloatData); |
| 161 | 137 |
| 162 // Compare against the expected result. | 138 // Compare against the expected result. |
| 163 var signal = signalBuffer.getChannelData(0); | 139 var signal = signalBuffer.getChannelData(0); |
| 164 var message = actualFloatData.length + "-point analyser time domain da
ta"; | 140 var message = actualFloatData.length + "-point analyser time domain da
ta"; |
| 165 success = Should(message, actualFloatData) | 141 should(actualFloatData, message) |
| 166 .beEqualToArray(signal.subarray(lastFrame - actualFloatData.length,
lastFrame)) && success; | 142 .beEqualToArray(signal.subarray(lastFrame - actualFloatData.length,
lastFrame)) && success; |
| 167 }).then(context.resume.bind(context)); | 143 }).then(context.resume.bind(context)); |
| 168 | 144 |
| 169 return context.startRendering(); | 145 return context.startRendering(); |
| 170 } | 146 } |
| 171 | 147 |
| 172 // Create the audio graph with an AnalyserNode with fftSize |fftSize|. A
simple | 148 // Create the audio graph with an AnalyserNode with fftSize |fftSize|. A
simple |
| 173 // integer-valued linear ramp is the source so we can easily verify the re
sults. A dictionary | 149 // integer-valued linear ramp is the source so we can easily verify the re
sults. A dictionary |
| 174 // consisting of the context, the analyser node, and the signal is returne
d. | 150 // consisting of the context, the analyser node, and the signal is returne
d. |
| 175 function createGraph(fftSize) { | 151 function createGraph(fftSize) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 196 | 172 |
| 197 return { | 173 return { |
| 198 context: context, | 174 context: context, |
| 199 analyser: analyser, | 175 analyser: analyser, |
| 200 signalBuffer: signalBuffer | 176 signalBuffer: signalBuffer |
| 201 }; | 177 }; |
| 202 } | 178 } |
| 203 </script> | 179 </script> |
| 204 </body> | 180 </body> |
| 205 </html> | 181 </html> |
| OLD | NEW |