| OLD | NEW |
| 1 <!doctype html> | 1 <!DOCTYPE html> |
| 2 <html> | 2 <html> |
| 3 <head> | 3 <head> |
| 4 <title>Test Different PeriodicWave Lengths at Different Sample Rates</title> | 4 <title> |
| 5 Test Different PeriodicWave Lengths at Different Sample Rates |
| 6 </title> |
| 5 <script src="../../resources/testharness.js"></script> | 7 <script src="../../resources/testharness.js"></script> |
| 6 <script src="../../resources/testharnessreport.js"></script> | 8 <script src="../../resources/testharnessreport.js"></script> |
| 7 <script src="../resources/audit-util.js"></script> | 9 <script src="../resources/audit-util.js"></script> |
| 8 <script src="../resources/audit.js"></script> | 10 <script src="../resources/audit.js"></script> |
| 9 </head> | 11 </head> |
| 12 <body> |
| 13 <script id="layout-test-code"> |
| 14 // Test PeriodicWave objects with varying number of coefficients at |
| 15 // different sample rates. Basically, verify that the coefficients are |
| 16 // used at the appropriate sample rates. This is done by comparing the |
| 17 // outputs of two periodic waves used in oscillators. The output should |
| 18 // either be exactly zero or not depending on whether the coefficients |
| 19 // were used. |
| 10 | 20 |
| 11 <body> | 21 let renderLength = 1; |
| 12 <script> | 22 let context; |
| 13 // Test PeriodicWave objects with varying number of coefficients at differ
ent sample rates. | |
| 14 // Basically, verify that the coefficients are used at the appropriate sam
ple rates. This is | |
| 15 // done by comparing the outputs of two periodic waves used in oscillators
. The output should | |
| 16 // either be exactly zero or not depending on whether the coefficients wer
e used. | |
| 17 | 23 |
| 18 var renderLength = 1; | 24 let audit = Audit.createTaskRunner(); |
| 19 var context; | |
| 20 | 25 |
| 21 var audit = Audit.createTaskRunner(); | 26 // The set of Audit tests to be run to verify that PeriodicWave is using |
| 27 // the correct number of coefficients. The name does not have to be |
| 28 // unique; the index of the entry is appended to the test. Every entry |
| 29 // (except the last) needs sampleRate, bigWave, smallWave, and verifier |
| 30 // values. |
| 22 | 31 |
| 23 // The set of Audit tests to be run to verify that PeriodicWave is using t
he correct number of | 32 let testSet = [ |
| 24 // coefficients. The name does not have to be unique; the index of the en
try is appended to | |
| 25 // the test. Every entry (except the last) needs sampleRate, bigWave, sma
llWave, and | |
| 26 // verifier values. | |
| 27 | |
| 28 var testSet = [ | |
| 29 // Tests for contexts at 192 kHz. | 33 // Tests for contexts at 192 kHz. |
| 30 | 34 |
| 31 // Test that we use more than 2048 Fourier coefficients at 192 kHz sampl
e rate. Basically | 35 // Test that we use more than 2048 Fourier coefficients at 192 kHz |
| 32 // verifies that 8192 is acceptable. | 36 // sample rate. Basically verifies that 8192 is acceptable. |
| 33 { | 37 { |
| 34 name: "192khz-test-1", | 38 name: '192khz-test-1', |
| 35 sampleRate: 192000, | 39 sampleRate: 192000, |
| 36 bigWave: 8192, | 40 bigWave: 8192, |
| 37 smallWave: 2048, | 41 smallWave: 2048, |
| 38 verifier: resultShouldBeNonZero | 42 verifier: resultShouldBeNonZero |
| 39 }, | 43 }, |
| 40 | 44 |
| 41 // Test that we use at least 2049 Fourier coefficients at 192 kHz sample
rate. | 45 // Test that we use at least 2049 Fourier coefficients at 192 kHz sample |
| 46 // rate. |
| 42 { | 47 { |
| 43 name: "192khz-test-2", | 48 name: '192khz-test-2', |
| 44 sampleRate: 192000, | 49 sampleRate: 192000, |
| 45 bigWave: 2049, | 50 bigWave: 2049, |
| 46 smallWave: 2048, | 51 smallWave: 2048, |
| 47 verifier: resultShouldBeNonZero | 52 verifier: resultShouldBeNonZero |
| 48 }, | 53 }, |
| 49 | 54 |
| 50 // Test that we use all 8192 Fourier coefficients at 192 kHz sample rate
. | 55 // Test that we use all 8192 Fourier coefficients at 192 kHz sample |
| 56 // rate. |
| 51 { | 57 { |
| 52 name: "192khz-test-3", | 58 name: '192khz-test-3', |
| 53 sampleRate: 192000, | 59 sampleRate: 192000, |
| 54 bigWave: 8192, | 60 bigWave: 8192, |
| 55 smallWave: 8191, | 61 smallWave: 8191, |
| 56 verifier: resultShouldBeNonZero | 62 verifier: resultShouldBeNonZero |
| 57 }, | 63 }, |
| 58 | 64 |
| 59 // Tests for contexts at 48 kHz. | 65 // Tests for contexts at 48 kHz. |
| 60 | 66 |
| 61 // Test that we do not use more than 2048 Fourier coefficients at 48 kHz
. This depends on | 67 // Test that we do not use more than 2048 Fourier coefficients at 48 |
| 62 // the internal implementation where, for backward compatibility and spe
ed, we only use 2048 | 68 // kHz. This depends on the internal implementation where, for backward |
| 63 // coefficients at 48 kHz. (This is also true for rates below 88.2 kHz.
) Also tests that | 69 // compatibility and speed, we only use 2048 coefficients at 48 kHz. |
| 64 // 8192 coefficients are allowed (but not all coefficients are used, of
course). | 70 // (This is also true for rates below 88.2 kHz.) Also tests that 8192 |
| 71 // coefficients are allowed (but not all coefficients are used, of |
| 72 // course). |
| 65 { | 73 { |
| 66 name: "48khz-test-1", | 74 name: '48khz-test-1', |
| 67 sampleRate: 48000, | 75 sampleRate: 48000, |
| 68 bigWave: 8192, | 76 bigWave: 8192, |
| 69 smallWave: 2048, | 77 smallWave: 2048, |
| 70 verifier: resultShouldBeZero | 78 verifier: resultShouldBeZero |
| 71 }, | 79 }, |
| 72 | 80 |
| 73 // Test that we do not use more than 2048 Fourier coefficients. | 81 // Test that we do not use more than 2048 Fourier coefficients. |
| 74 { | 82 { |
| 75 name: "48khz-test-2", | 83 name: '48khz-test-2', |
| 76 sampleRate: 48000, | 84 sampleRate: 48000, |
| 77 bigWave: 2049, | 85 bigWave: 2049, |
| 78 smallWave: 2048, | 86 smallWave: 2048, |
| 79 verifier: resultShouldBeZero | 87 verifier: resultShouldBeZero |
| 80 }, | 88 }, |
| 81 | 89 |
| 82 // It's not immediately clear with single-preicison arithmetic that we c
an distinguish | 90 // It's not immediately clear with single-preicison arithmetic that we |
| 83 // between 2049 and 2048 coefficients, so do one more test with slightly
more coefficients. | 91 // can distinguish between 2049 and 2048 coefficients, so do one more |
| 92 // test with slightly more coefficients. |
| 84 { | 93 { |
| 85 name: "48khz-test-3", | 94 name: '48khz-test-3', |
| 86 sampleRate: 48000, | 95 sampleRate: 48000, |
| 87 bigWave: (2 + 1 / 64) * 1024, | 96 bigWave: (2 + 1 / 64) * 1024, |
| 88 smallWave: 2048, | 97 smallWave: 2048, |
| 89 verifier: resultShouldBeZero | 98 verifier: resultShouldBeZero |
| 90 }, | 99 }, |
| 91 | 100 |
| 92 // Test that we use at least 2048 Fourier coefficients at 48 kHz. Ideal
ly we want to | 101 // Test that we use at least 2048 Fourier coefficients at 48 kHz. |
| 93 // compare 2047 and 2048 coefficients, but single-precision arithmetic m
akes the resulting | 102 // Ideally we want to compare 2047 and 2048 coefficients, but |
| 94 // waveforms the same. Hence use a smaller value that produces differen
t waveforms. | 103 // single-precision arithmetic makes the resulting waveforms the same. |
| 104 // Hence use a smaller value that produces different waveforms. |
| 95 { | 105 { |
| 96 name: "48khz-test-4", | 106 name: '48khz-test-4', |
| 97 sampleRate: 48000, | 107 sampleRate: 48000, |
| 98 bigWave: 2048, | 108 bigWave: 2048, |
| 99 smallWave: 2046, | 109 smallWave: 2046, |
| 100 verifier: resultShouldBeNonZero | 110 verifier: resultShouldBeNonZero |
| 101 }, | 111 }, |
| 102 | 112 |
| 103 // Tests for contexts at 24 kHz. | 113 // Tests for contexts at 24 kHz. |
| 104 | 114 |
| 105 // Test that we do not use more than 1024 Fourier coefficients at 24 kHz
. | 115 // Test that we do not use more than 1024 Fourier coefficients at 24 |
| 116 // kHz. |
| 106 { | 117 { |
| 107 name: "24khz-test-1", | 118 name: '24khz-test-1', |
| 108 sampleRate: 24000, | 119 sampleRate: 24000, |
| 109 bigWave: 8192, | 120 bigWave: 8192, |
| 110 smallWave: 1024, | 121 smallWave: 1024, |
| 111 verifier: resultShouldBeZero | 122 verifier: resultShouldBeZero |
| 112 }, | 123 }, |
| 113 | 124 |
| 114 // Test that we do not use more than 1024 Fourier coefficients at 24 kHz
. | 125 // Test that we do not use more than 1024 Fourier coefficients at 24 |
| 126 // kHz. |
| 115 { | 127 { |
| 116 name: "24khz-test-2", | 128 name: '24khz-test-2', |
| 117 sampleRate: 24000, | 129 sampleRate: 24000, |
| 118 bigWave: 1025, | 130 bigWave: 1025, |
| 119 smallWave: 1024, | 131 smallWave: 1024, |
| 120 verifier: resultShouldBeZero | 132 verifier: resultShouldBeZero |
| 121 }, | 133 }, |
| 122 | 134 |
| 123 // Test that we use at least 1024 Fourier coefficients at 24 kHz. Again
, 1023 and 1024 | 135 // Test that we use at least 1024 Fourier coefficients at 24 kHz. |
| 124 // produce the same waveforms in single-precisiion so use a smaller wave
table size. | 136 // Again, 1023 and 1024 produce the same waveforms in single-precisiion |
| 137 // so use a smaller wave table size. |
| 125 { | 138 { |
| 126 name: "24khz-test-3", | 139 name: '24khz-test-3', |
| 127 sampleRate: 24000, | 140 sampleRate: 24000, |
| 128 bigWave: 1024, | 141 bigWave: 1024, |
| 129 smallWave: 1022, | 142 smallWave: 1022, |
| 130 verifier: resultShouldBeNonZero | 143 verifier: resultShouldBeNonZero |
| 131 }, | 144 }, |
| 132 ]; | 145 ]; |
| 133 | 146 |
| 134 function generatePrefix (sampleRate, bigLength, smallLength) { | 147 function generatePrefix(sampleRate, bigLength, smallLength) { |
| 135 return "At " + (sampleRate / 1000) + " kHz, PeriodicWave with " | 148 return 'At ' + (sampleRate / 1000) + ' kHz, PeriodicWave with ' + |
| 136 + bigLength + " coefficients vs " | 149 bigLength + ' coefficients vs ' + smallLength + ': '; |
| 137 + smallLength + ": "; | |
| 138 } | 150 } |
| 139 | 151 |
| 140 // Returns a function the verifies that the result is zero. The parameter
s control what is | 152 // Returns a function the verifies that the result is zero. The |
| 141 // printed in the messages. | 153 // parameters control what is printed in the messages. |
| 142 function resultShouldBeZero(should, sampleRate, bigLength, smallLength) { | 154 function resultShouldBeZero(should, sampleRate, bigLength, smallLength) { |
| 143 return function (buffer) { | 155 return function(buffer) { |
| 144 var prefix = generatePrefix(sampleRate, bigLength, smallLength); | 156 let prefix = generatePrefix(sampleRate, bigLength, smallLength); |
| 145 should(isBufferZero(buffer), prefix + "are identical") | 157 should(isBufferZero(buffer), prefix + 'are identical') |
| 146 .beEqualTo(true); | 158 .beEqualTo(true); |
| 147 } | 159 } |
| 148 } | 160 } |
| 149 | 161 |
| 150 // Returns a function the verifies that the result is non-zero. The param
eters control what is | 162 // Returns a function the verifies that the result is non-zero. The |
| 151 // printed in the messages. | 163 // parameters control what is printed in the messages. |
| 152 function resultShouldBeNonZero(should, sampleRate, bigLength, smallLength)
{ | 164 function resultShouldBeNonZero( |
| 153 return function (buffer) { | 165 should, sampleRate, bigLength, smallLength) { |
| 154 var prefix = generatePrefix(sampleRate, bigLength, smallLength); | 166 return function(buffer) { |
| 155 should(!isBufferZero(buffer), prefix + "are different") | 167 let prefix = generatePrefix(sampleRate, bigLength, smallLength); |
| 156 .beEqualTo(true); | 168 should(!isBufferZero(buffer), prefix + 'are different') |
| 169 .beEqualTo(true); |
| 157 } | 170 } |
| 158 } | 171 } |
| 159 | 172 |
| 160 // Creates a function that is used to run an Audit test for a given sample
rate, periodic wave | 173 // Creates a function that is used to run an Audit test for a given sample |
| 161 // sizes, and verifier. | 174 // rate, periodic wave sizes, and verifier. |
| 162 function createAuditTestFunction(sampleRate, bigLength, smallLength, verif
ier) { | 175 function createAuditTestFunction( |
| 163 return (task, should) => { | 176 sampleRate, bigLength, smallLength, verifier) { |
| 164 // Create the audio graph, render it, and then verify that the output
is the expected | 177 return (task, should) => { |
| 165 // result. | 178 // Create the audio graph, render it, and then verify that the output |
| 166 createAudioGraph(sampleRate, bigLength, smallLength); | 179 // is the expected result. |
| 180 createAudioGraph(sampleRate, bigLength, smallLength); |
| 167 | 181 |
| 168 return context.startRendering() | 182 return context.startRendering() |
| 169 .then(verifier(should, sampleRate, bigLength, smallLength)) | 183 .then(verifier(should, sampleRate, bigLength, smallLength)) |
| 170 .then(() => task.done()); | 184 .then(() => task.done()); |
| 171 } | 185 } |
| 172 } | 186 } |
| 173 | 187 |
| 174 // Create the audio graph for the test. | 188 // Create the audio graph for the test. |
| 175 function createAudioGraph(sampleRate, bigPeriodicWaveLength, smallPeriodic
WaveLength) { | 189 function createAudioGraph( |
| 176 context = new OfflineAudioContext(1, renderLength * sampleRate, sampleR
ate); | 190 sampleRate, bigPeriodicWaveLength, smallPeriodicWaveLength) { |
| 191 context = |
| 192 new OfflineAudioContext(1, renderLength * sampleRate, sampleRate); |
| 177 | 193 |
| 178 // Two PeriodicWave objects are created with different sizes (small and
big). The contents | 194 // Two PeriodicWave objects are created with different sizes (small and |
| 179 // are the same except that the samll sized PeriodicWave has fewer coef
ficients. | 195 // big). The contents are the same except that the samll sized |
| 180 var smallWaveRealCoef = new Float32Array(smallPeriodicWaveLength); | 196 // PeriodicWave has fewer coefficients. |
| 181 var smallWaveImagCoef = new Float32Array(smallPeriodicWaveLength); | 197 let smallWaveRealCoef = new Float32Array(smallPeriodicWaveLength); |
| 182 var bigWaveRealCoef = new Float32Array(bigPeriodicWaveLength); | 198 let smallWaveImagCoef = new Float32Array(smallPeriodicWaveLength); |
| 183 var bigWaveImagCoef = new Float32Array(bigPeriodicWaveLength); | 199 let bigWaveRealCoef = new Float32Array(bigPeriodicWaveLength); |
| 200 let bigWaveImagCoef = new Float32Array(bigPeriodicWaveLength); |
| 184 | 201 |
| 185 // Set up the Fourier coefficients for a sawtooth wave. We use | 202 // Set up the Fourier coefficients for a sawtooth wave. We use |
| 186 // sawtooth because all coefficients are non-zero | 203 // sawtooth because all coefficients are non-zero |
| 187 bigWaveImagCoef[0] = 0; | 204 bigWaveImagCoef[0] = 0; |
| 188 for (var k = 1; k < bigPeriodicWaveLength; k++) { | 205 for (let k = 1; k < bigPeriodicWaveLength; k++) { |
| 189 var piFactor = 2 / (Math.PI * k); | 206 let piFactor = 2 / (Math.PI * k); |
| 190 bigWaveImagCoef[k] = piFactor * ((k % 2 === 0) ? -1 : 1); | 207 bigWaveImagCoef[k] = piFactor * ((k % 2 === 0) ? -1 : 1); |
| 191 if (k < smallPeriodicWaveLength) | 208 if (k < smallPeriodicWaveLength) |
| 192 smallWaveImagCoef[k] = bigWaveImagCoef[k]; | 209 smallWaveImagCoef[k] = bigWaveImagCoef[k]; |
| 193 } | 210 } |
| 194 | |
| 195 var smallPeriodicWave = context.createPeriodicWave(smallWaveRealCoef, s
mallWaveImagCoef); | |
| 196 var bigPeriodicWave = context.createPeriodicWave(bigWaveRealCoef, bigWa
veImagCoef); | |
| 197 | 211 |
| 198 // Create oscillators using these PeriodicWave's. | 212 let smallPeriodicWave = |
| 199 var smallOscillator = context.createOscillator(); | 213 context.createPeriodicWave(smallWaveRealCoef, smallWaveImagCoef); |
| 200 var bigOscillator = context.createOscillator(); | 214 let bigPeriodicWave = |
| 215 context.createPeriodicWave(bigWaveRealCoef, bigWaveImagCoef); |
| 201 | 216 |
| 202 smallOscillator.setPeriodicWave(smallPeriodicWave); | 217 // Create oscillators using these PeriodicWave's. |
| 203 bigOscillator.setPeriodicWave(bigPeriodicWave); | 218 let smallOscillator = context.createOscillator(); |
| 219 let bigOscillator = context.createOscillator(); |
| 204 | 220 |
| 205 // Use a frequency of 1 Hz to make the distinction easier. Can't tell
from this test, but | 221 smallOscillator.setPeriodicWave(smallPeriodicWave); |
| 206 // if you plot the signals from these oscillators, it's very clear that
they are different. | 222 bigOscillator.setPeriodicWave(bigPeriodicWave); |
| 207 smallOscillator.frequency.value = 1; | |
| 208 bigOscillator.frequency.value = 1; | |
| 209 | 223 |
| 210 // The desired output is the difference between these oscillators. | 224 // Use a frequency of 1 Hz to make the distinction easier. Can't tell |
| 211 var gain = context.createGain(); | 225 // from this test, but if you plot the signals from these oscillators, |
| 212 gain.gain.value = -1; | 226 // it's very clear that they are different. |
| 213 smallOscillator.connect(gain); | 227 smallOscillator.frequency.value = 1; |
| 228 bigOscillator.frequency.value = 1; |
| 214 | 229 |
| 215 gain.connect(context.destination); | 230 // The desired output is the difference between these oscillators. |
| 216 bigOscillator.connect(context.destination); | 231 let gain = context.createGain(); |
| 232 gain.gain.value = -1; |
| 233 smallOscillator.connect(gain); |
| 217 | 234 |
| 218 // Start the oscillators. | 235 gain.connect(context.destination); |
| 219 smallOscillator.start(); | 236 bigOscillator.connect(context.destination); |
| 220 bigOscillator.start(); | 237 |
| 238 // Start the oscillators. |
| 239 smallOscillator.start(); |
| 240 bigOscillator.start(); |
| 221 } | 241 } |
| 222 | 242 |
| 223 // Return true if the buffer is exactly zero. | 243 // Return true if the buffer is exactly zero. |
| 224 function isBufferZero(buffer) { | 244 function isBufferZero(buffer) { |
| 225 if (buffer.getChannelData(0).find(function (x) { return x != 0; })) | 245 if (buffer.getChannelData(0).find(function(x) { |
| 246 return x != 0; |
| 247 })) |
| 226 return false; | 248 return false; |
| 227 return true; | 249 return true; |
| 228 } | 250 } |
| 229 | 251 |
| 230 // Ensure the actual Audit test name is unique by prepending an index to t
he provided test | 252 // Ensure the actual Audit test name is unique by prepending an index to |
| 231 // name. | 253 // the provided test name. |
| 232 function actualTestName(name, index) { | 254 function actualTestName(name, index) { |
| 233 return index + ":" + name; | 255 return index + ':' + name; |
| 234 } | 256 } |
| 235 | 257 |
| 236 // Define the tasks based on the entries in testSet. | 258 // Define the tasks based on the entries in testSet. |
| 237 function defineAuditTests() { | 259 function defineAuditTests() { |
| 238 for (var k = 0; k < testSet.length; ++k) { | 260 for (let k = 0; k < testSet.length; ++k) { |
| 239 let {name, sampleRate, bigWave, smallWave, verifier} = testSet[k]; | 261 let {name, sampleRate, bigWave, smallWave, verifier} = testSet[k]; |
| 240 let actualName = actualTestName(name, k); | 262 let actualName = actualTestName(name, k); |
| 241 audit.define(actualName, | 263 audit.define( |
| 242 createAuditTestFunction(sampleRate, bigWave, smallWave, verifier)); | 264 actualName, |
| 265 createAuditTestFunction( |
| 266 sampleRate, bigWave, smallWave, verifier)); |
| 243 } | 267 } |
| 244 } | 268 } |
| 245 | 269 |
| 246 defineAuditTests(); | 270 defineAuditTests(); |
| 247 audit.run(); | 271 audit.run(); |
| 248 </script> | 272 </script> |
| 249 </body> | 273 </body> |
| 250 </html> | 274 </html> |
| OLD | NEW |