| OLD | NEW |
| 1 // Notes about generated waveforms: | 1 // Notes about generated waveforms: |
| 2 // | 2 // |
| 3 // QUESTION: Why does the wave shape not look like the exact shape (sharp edges)
? | 3 // QUESTION: Why does the wave shape not look like the exact shape (sharp edges)
? |
| 4 // ANSWER: Because a shape with sharp edges has infinitely high frequency conten
t. | 4 // ANSWER: Because a shape with sharp edges has infinitely high frequency conten
t. |
| 5 // Since a digital audio signal must be band-limited based on the nyquist freque
ncy (half the sample-rate) | 5 // Since a digital audio signal must be band-limited based on the nyquist freque
ncy (half the sample-rate) |
| 6 // in order to avoid aliasing, this creates more rounded edges and "ringing" in
the | 6 // in order to avoid aliasing, this creates more rounded edges and "ringing" in
the |
| 7 // appearance of the waveform. See Nyquist-Shannon sampling theorem: | 7 // appearance of the waveform. See Nyquist-Shannon sampling theorem: |
| 8 // http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem | 8 // http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem |
| 9 // | 9 // |
| 10 // QUESTION: Why does the very end of the generated signal appear to get slightl
y weaker? | 10 // QUESTION: Why does the very end of the generated signal appear to get slightl
y weaker? |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 | 60 |
| 61 // Count the number of differences between the expected and actual result. The t
ests passes | 61 // Count the number of differences between the expected and actual result. The t
ests passes |
| 62 // if the count is less than this threshold. | 62 // if the count is less than this threshold. |
| 63 var thresholdDiffCount = 0; | 63 var thresholdDiffCount = 0; |
| 64 | 64 |
| 65 // Mostly for debugging | 65 // Mostly for debugging |
| 66 | 66 |
| 67 // An AudioBuffer for the reference (expected) result. | 67 // An AudioBuffer for the reference (expected) result. |
| 68 var reference = 0; | 68 var reference = 0; |
| 69 | 69 |
| 70 // The actual rendered data produced by the test. | |
| 71 var renderedData = 0; | |
| 72 | |
| 73 // Signal power of the reference | 70 // Signal power of the reference |
| 74 var signalPower = 0; | 71 var signalPower = 0; |
| 75 | 72 |
| 76 // Noise power of the difference between the reference and actual result. | 73 // Noise power of the difference between the reference and actual result. |
| 77 var noisePower = 0; | 74 var noisePower = 0; |
| 78 | 75 |
| 79 function generateExponentialOscillatorSweep(context, oscillatorType) { | 76 function generateExponentialOscillatorSweep(context, oscillatorType) { |
| 80 var osc = context.createOscillator(); | 77 var osc = context.createOscillator(); |
| 81 if (oscillatorType == "custom") { | 78 if (oscillatorType == "custom") { |
| 82 // Create a simple waveform with three Fourier coefficients. | 79 // Create a simple waveform with three Fourier coefficients. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 102 } | 99 } |
| 103 | 100 |
| 104 function calculateSNR(sPower, nPower) | 101 function calculateSNR(sPower, nPower) |
| 105 { | 102 { |
| 106 if (nPower == 0 && sPower > 0) { | 103 if (nPower == 0 && sPower > 0) { |
| 107 return 1000; | 104 return 1000; |
| 108 } | 105 } |
| 109 return 10 * Math.log10(sPower / nPower); | 106 return 10 * Math.log10(sPower / nPower); |
| 110 } | 107 } |
| 111 | 108 |
| 112 function loadReferenceAndRunTest(oscType) { | 109 function loadReferenceAndRunTest(context, oscType, task, should) { |
| 113 var bufferLoader = new BufferLoader( | 110 var bufferLoader = new BufferLoader( |
| 114 context, | 111 context, |
| 115 [ "../Oscillator/oscillator-" + oscType + "-expected.wav" ], | 112 [ "../Oscillator/oscillator-" + oscType + "-expected.wav" ], |
| 116 function (bufferList) { | 113 function (bufferList) { |
| 117 reference = bufferList[0].getChannelData(0); | 114 reference = bufferList[0].getChannelData(0); |
| 118 generateExponentialOscillatorSweep(context, oscType); | 115 generateExponentialOscillatorSweep(context, oscType); |
| 119 context.oncomplete = checkResult; | 116 context.oncomplete = () => { |
| 117 checkResult(event, should); |
| 118 task.done(); |
| 119 }; |
| 120 context.startRendering(); | 120 context.startRendering(); |
| 121 }); | 121 }); |
| 122 | 122 |
| 123 bufferLoader.load(); | 123 bufferLoader.load(); |
| 124 } | 124 } |
| 125 | 125 |
| 126 function checkResult (event) { | 126 function checkResult (event, should) { |
| 127 renderedData = event.renderedBuffer.getChannelData(0); | 127 let renderedData = event.renderedBuffer.getChannelData(0); |
| 128 // Compute signal to noise ratio between the result and the reference. Also
keep track | 128 // Compute signal to noise ratio between the result and the reference. Also
keep track |
| 129 // of the max difference (and position). | 129 // of the max difference (and position). |
| 130 | 130 |
| 131 var maxError = -1; | 131 var maxError = -1; |
| 132 var errorPosition = -1; | 132 var errorPosition = -1; |
| 133 var diffCount = 0; | 133 var diffCount = 0; |
| 134 | 134 |
| 135 for (var k = 0; k < renderedData.length; ++k) { | 135 for (var k = 0; k < renderedData.length; ++k) { |
| 136 var diff = renderedData[k] - reference[k]; | 136 var diff = renderedData[k] - reference[k]; |
| 137 noisePower += diff * diff; | 137 noisePower += diff * diff; |
| 138 signalPower += reference[k] * reference[k]; | 138 signalPower += reference[k] * reference[k]; |
| 139 if (Math.abs(diff) > maxError) { | 139 if (Math.abs(diff) > maxError) { |
| 140 maxError = Math.abs(diff); | 140 maxError = Math.abs(diff); |
| 141 errorPosition = k; | 141 errorPosition = k; |
| 142 } | 142 } |
| 143 // The reference file is a 16-bit WAV file, so we will almost never get
an exact match | 143 // The reference file is a 16-bit WAV file, so we will almost never get
an exact match |
| 144 // between it and the actual floating-point result. | 144 // between it and the actual floating-point result. |
| 145 if (diff > 1/waveScaleFactor) { | 145 if (diff > 1/waveScaleFactor) { |
| 146 diffCount++; | 146 diffCount++; |
| 147 } | 147 } |
| 148 } | 148 } |
| 149 | 149 |
| 150 var snr = calculateSNR(signalPower, noisePower); | 150 var snr = calculateSNR(signalPower, noisePower); |
| 151 if (snr >= thresholdSNR) { | 151 should(snr, "SNR") |
| 152 testPassed("Exceeded SNR threshold of " + thresholdSNR + " dB"); | 152 .beGreaterThanOrEqualTo(thresholdSNR); |
| 153 } else { | 153 should(maxError * waveScaleFactor, "Maximum difference in ulp (16-bits)") |
| 154 testFailed("Expected SNR of " + thresholdSNR + " dB, but actual SNR is "
+ snr + " dB"); | 154 .beLessThanOrEqualTo(thresholdDiff * waveScaleFactor); |
| 155 } | |
| 156 | 155 |
| 157 if (maxError <= thresholdDiff) { | 156 should(diffCount, |
| 158 testPassed("Maximum difference below threshold of " | 157 "Number of differences between actual and expected result out of " |
| 159 + (thresholdDiff * waveScaleFactor) + " ulp (16-bits)"); | 158 + renderedData.length + " frames") |
| 160 } else { | 159 .beLessThanOrEqualTo(thresholdDiffCount); |
| 161 testFailed("Maximum difference of " + (maxError * waveScaleFactor) + " a
t " | |
| 162 + errorPosition + " exceeded threshold of " + (thresholdDiff
* waveScaleFactor) | |
| 163 + " ulp (16-bits)"); | |
| 164 } | |
| 165 | |
| 166 if (diffCount <= thresholdDiffCount) { | |
| 167 testPassed("Number of differences between actual and expected result is
less than " + thresholdDiffCount | |
| 168 + " out of " + renderedData.length); | |
| 169 } else { | |
| 170 testFailed(diffCount + " differences found but expected no more than " +
thresholdDiffCount | |
| 171 + " out of " + renderedData.length); | |
| 172 } | |
| 173 | |
| 174 finishJSTest(); | |
| 175 } | 160 } |
| 176 | 161 |
| 177 function setThresholds(thresholds) { | 162 function setThresholds(thresholds) { |
| 178 thresholdSNR = thresholds.snr; | 163 thresholdSNR = thresholds.snr; |
| 179 thresholdDiff = thresholds.maxDiff / waveScaleFactor; | 164 thresholdDiff = thresholds.maxDiff / waveScaleFactor; |
| 180 thresholdDiffCount = thresholds.diffCount; | 165 thresholdDiffCount = thresholds.diffCount; |
| 181 } | 166 } |
| 182 | 167 |
| 183 function runTest(oscType) { | 168 function runTest(context, oscType, description, task, should) { |
| 184 window.jsTestIsAsync = true; | 169 loadReferenceAndRunTest(context, oscType, task, should); |
| 185 context = new OfflineAudioContext(1, sampleRate * lengthInSeconds, sampleRat
e); | |
| 186 loadReferenceAndRunTest(oscType); | |
| 187 } | 170 } |
| 188 | 171 |
| 189 function createNewReference(oscType) { | 172 function createNewReference(oscType) { |
| 190 if (!window.testRunner) | 173 if (!window.testRunner) |
| 191 return; | 174 return; |
| 192 | 175 |
| 193 context = new OfflineAudioContext(1, sampleRate * lengthInSeconds, sampleRa
te); | 176 context = new OfflineAudioContext(1, sampleRate * lengthInSeconds, sampleRa
te); |
| 194 generateExponentialOscillatorSweep(context, oscType); | 177 generateExponentialOscillatorSweep(context, oscType); |
| 195 | 178 |
| 196 context.oncomplete = finishAudioTest; | 179 context.oncomplete = finishAudioTest; |
| 197 context.startRendering(); | 180 context.startRendering(); |
| 198 | 181 |
| 199 testRunner.waitUntilDone(); | 182 testRunner.waitUntilDone(); |
| 200 } | 183 } |
| 201 | 184 |
| 202 return { | 185 return { |
| 203 sampleRate: sampleRate, | 186 sampleRate: sampleRate, |
| 204 lengthInSeconds: lengthInSeconds, | 187 lengthInSeconds: lengthInSeconds, |
| 205 thresholdSNR: thresholdSNR, | 188 thresholdSNR: thresholdSNR, |
| 206 thresholdDiff: thresholdDiff, | 189 thresholdDiff: thresholdDiff, |
| 207 thresholdDiffCount: thresholdDiffCount, | 190 thresholdDiffCount: thresholdDiffCount, |
| 208 waveScaleFactor: waveScaleFactor, | 191 waveScaleFactor: waveScaleFactor, |
| 209 setThresholds: setThresholds, | 192 setThresholds: setThresholds, |
| 210 loadReferenceAndRunTest: loadReferenceAndRunTest, | |
| 211 runTest: runTest, | 193 runTest: runTest, |
| 212 createNewReference: createNewReference, | 194 createNewReference: createNewReference, |
| 213 }; | 195 }; |
| 214 | 196 |
| 215 }()); | 197 }()); |
| OLD | NEW |