| <!DOCTYPE html> |
| <html> |
| <head> |
| <title> |
| Handle Silent Inputs to AnalyserNode |
| </title> |
| <script src="../../imported/w3c/web-platform-tests/resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| <script src="../resources/audit-util.js"></script> |
| <script src="../resources/audit.js"></script> |
| </head> |
| <body> |
| <script id="layout-test-code"> |
| let audit = Audit.createTaskRunner(); |
| let sampleRate = 16000; |
| let renderDuration = 1; |
| let renderFrames = renderDuration * sampleRate; |
| |
| audit.define( |
| {label: 'connected', description: 'Test handling of silent inputs'}, |
| function(task, should) { |
| tester(should, false, '0').then(task.done.bind(task)); |
| }); |
| |
| audit.define( |
| {label: 'auto-pull', description: 'Test handling of silent inputs'}, |
| function(task, should) { |
| tester(should, true, '1').then(task.done.bind(task)); |
| }); |
| |
| audit.define( |
| { |
| label: 'timing', |
| description: 'Test shifting in of zeroes after source has stopped' |
| }, |
| function(task, should) { |
| let renderQuantumFrames = 128; |
| |
| // sampleRate chosen to be a power of two so we don't have round-off |
| // errors in computing the times for when to suspend the context. |
| let context = new OfflineAudioContext(1, 16384, 16384); |
| let source = new ConstantSourceNode(context); |
| |
| // The fftSize for the analyser is fairly arbitrary, except the code |
| // assumes it is larger than 128. |
| let analyser = new AnalyserNode(context, {fftSize: 2048}); |
| |
| source.connect(analyser).connect(context.destination); |
| |
| source.start(); |
| |
| // Stop the source after 1 fftSize frames. |
| let time = analyser.fftSize / context.sampleRate; |
| source.stop(time); |
| |
| // Verify that the time data at this point is constant. |
| context.suspend(time) |
| .then(() => { |
| let data = new Float32Array(analyser.fftSize); |
| analyser.getFloatTimeDomainData(data); |
| should( |
| data, |
| 'At time ' + context.currentTime + |
| ' Analyser frames [0, ' + analyser.fftSize + ')') |
| .beConstantValueOf(1); |
| }) |
| .then(context.resume.bind(context)); |
| |
| // After each rendering quantum from the point at which the source |
| // stopped, verify that zeroes are inserted into the time data one |
| // rendering quantum at a time. |
| |
| let limit = analyser.fftSize / renderQuantumFrames; |
| |
| for (let k = 1; k <= limit; ++k) { |
| let analyserTime = (analyser.fftSize + k * renderQuantumFrames) / |
| context.sampleRate; |
| context.suspend(analyserTime) |
| .then(() => { |
| let data = new Float32Array(analyser.fftSize); |
| let indexNewest = |
| analyser.fftSize - k * renderQuantumFrames; |
| analyser.getFloatTimeDomainData(data); |
| if (k < limit) { |
| should( |
| data.slice(0, indexNewest), |
| 'At time ' + context.currentTime + |
| ' Analyser frames [0, ' + indexNewest + ')') |
| .beConstantValueOf(1); |
| } |
| should( |
| data.slice(indexNewest), |
| 'At time ' + context.currentTime + |
| ' Analyser frames [' + indexNewest + ', ' + |
| analyser.fftSize + ')') |
| .beConstantValueOf(0); |
| }) |
| .then(context.resume.bind(context)); |
| } |
| |
| // Start the test |
| context.startRendering().then(() => task.done()); |
| }); |
| |
| audit.run(); |
| |
| function tester(should, isAutoPullTest, prefix) { |
| // Connect an oscillator to an analyser for testing the time data of the |
| // analyser after the oscillator stops. |
| let context = new OfflineAudioContext(1, renderFrames, sampleRate); |
| let source = new OscillatorNode(context); |
| let analyser = new AnalyserNode(context, {fftSize: 128}); |
| let timeData = new Float32Array(analyser.fftSize); |
| timeData.fill(NaN); |
| |
| source.connect(analyser); |
| |
| // For the automatic pull test, leave the analyser output disconnected. |
| if (isAutoPullTest) { |
| source.connect(context.destination); |
| } else { |
| analyser.connect(context.destination); |
| } |
| |
| source.start(); |
| |
| // Stop the source well in advance of when we want to get the time data |
| // from the analyser. |
| let stopTime = 0.1; |
| let dataTime = 0.5; |
| |
| source.stop(stopTime); |
| context.suspend(dataTime) |
| .then(() => { |
| analyser.getFloatTimeDomainData(timeData); |
| }) |
| .then(context.resume.bind(context)); |
| |
| return context.startRendering().then(buffer => { |
| should(timeData, prefix + ': Analyser time data at time ' + dataTime) |
| .beConstantValueOf(0); |
| }); |
| } |
| </script> |
| </body> |
| </html> |