| <!DOCTYPE html> |
| <html> |
| <head> |
| <title> |
| Test Analyser.getByteTimeDomainData() |
| </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 sampleRate = 48000; |
| // The size of the analyser frame. Anything larger than 128 is ok, but |
| // should be long enough to capture the peaks of the oscillator waveform. |
| let fftSize = 256; |
| // Number of frames to render. Should be greater than the fftSize, but is |
| // otherwise arbitrary. |
| let renderFrames = 2 * fftSize; |
| |
| let audit = Audit.createTaskRunner(); |
| |
| // Test that getByteTimeDomainData returns the correct values. This test |
| // depends on getFloatTimeDomainData returning the correct data (for which |
| // there is already a test). |
| audit.define('byte-data', (task, should) => { |
| let context = new OfflineAudioContext(1, renderFrames, sampleRate); |
| |
| // Create a sawtooth as the signal under test. A sine wave or triangle |
| // wave would probably also work. |
| let src = context.createOscillator(); |
| src.type = 'sawtooth'; |
| // Choose a frequency high enough that we get at least a full period in |
| // one analyser fftSize frame. Otherwise, the frequency is arbitrary. |
| src.frequency.value = 440; |
| |
| // Gain node to make sure the signal goes somewhat above 1, for testing |
| // clipping. |
| let gain = context.createGain(); |
| gain.gain.value = 1.5; |
| |
| // The analyser node to test |
| let analyser = context.createAnalyser(); |
| analyser.fftSize = fftSize; |
| |
| // Connect the graph. |
| src.connect(gain); |
| gain.connect(analyser); |
| analyser.connect(context.destination); |
| |
| // Stop rendering after one analyser frame so we can grab the data. |
| context.suspend(fftSize / sampleRate) |
| .then(function() { |
| let floatData = new Float32Array(fftSize); |
| let byteData = new Uint8Array(fftSize); |
| |
| analyser.getFloatTimeDomainData(floatData); |
| analyser.getByteTimeDomainData(byteData); |
| |
| // Use the float data to compute the expected value for the byte |
| // data. |
| let expected = new Float32Array(fftSize); |
| for (let k = 0; k < fftSize; ++k) { |
| // It's important to do Math.fround to match the |
| // single-precision float in the implementation! |
| let value = Math.fround(128 * Math.fround(1 + floatData[k])); |
| // Clip the result to lie in the range [0, 255]. |
| expected[k] = Math.floor(Math.min(255, Math.max(0, value))); |
| } |
| |
| // Find the first index of the first sample that exceeds +1 or -1. |
| // The test MUST have at least one such value. |
| let indexMax = floatData.findIndex(function(x) { |
| return x > 1; |
| }); |
| let indexMin = floatData.findIndex(function(x) { |
| return x < -1; |
| }); |
| |
| should(indexMax, 'Index of first sample greater than +1') |
| .beGreaterThanOrEqualTo(0); |
| should(indexMin, 'Index of first sample less than -1') |
| .beGreaterThanOrEqualTo(0); |
| |
| // Verify explicitly that clipping happened correctly at the above |
| // indices. |
| should( |
| byteData[indexMax], |
| 'Clip ' + floatData[indexMax].toPrecision(6) + |
| ': byteData[' + indexMax + ']') |
| .beEqualTo(255); |
| should( |
| byteData[indexMin], |
| 'Clip ' + floatData[indexMin].toPrecision(6) + ': byteData[' + |
| indexMin + ']') |
| .beEqualTo(0); |
| |
| // Verify that all other samples are computed correctly. |
| should(byteData, 'Byte data').beEqualToArray(expected); |
| }) |
| .then(context.resume.bind(context)) |
| |
| src.start(); |
| context.startRendering().then(() => task.done()); |
| }); |
| |
| audit.run(); |
| </script> |
| </body> |
| </html> |