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