Chromium Code Reviews| 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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 78 gainNode.connect(context.destination); | 78 gainNode.connect(context.destination); |
| 79 | 79 |
| 80 osc.start(0); | 80 osc.start(0); |
| 81 | 81 |
| 82 osc.frequency.setValueAtTime(10, 0); | 82 osc.frequency.setValueAtTime(10, 0); |
| 83 osc.frequency.exponentialRampToValueAtTime(highFrequency, lengthInSeconds); | 83 osc.frequency.exponentialRampToValueAtTime(highFrequency, lengthInSeconds); |
| 84 } | 84 } |
| 85 | 85 |
| 86 function calculateSNR(sPower, nPower) | 86 function calculateSNR(sPower, nPower) |
| 87 { | 87 { |
| 88 if (nPower == 0 && sPower > 0) { | |
| 89 return 1000; | |
| 90 } | |
| 91 return 10 * Math.log10(sPower / nPower); | 88 return 10 * Math.log10(sPower / nPower); |
| 92 } | 89 } |
| 93 | 90 |
| 94 function loadReferenceAndRunTest(context, oscType, task, should) { | 91 function loadReferenceAndRunTest(context, oscType, task, should) { |
| 92 /* | |
| 95 var bufferLoader = new BufferLoader( | 93 var bufferLoader = new BufferLoader( |
| 96 context, | 94 context, |
| 97 [ "../Oscillator/oscillator-" + oscType + "-expected.wav" ], | 95 [ "../Oscillator/oscillator-" + oscType + "-expected.wav" ], |
| 98 function (bufferList) { | 96 function (bufferList) { |
| 99 reference = bufferList[0].getChannelData(0); | 97 reference = bufferList[0].getChannelData(0); |
| 100 generateExponentialOscillatorSweep(context, oscType); | 98 generateExponentialOscillatorSweep(context, oscType); |
| 101 context.oncomplete = () => { | 99 context.oncomplete = () => { |
| 102 checkResult(event, should, oscType); | 100 checkResult(event, should, oscType); |
| 103 task.done(); | 101 task.done(); |
| 104 }; | 102 }; |
| 105 context.startRendering(); | 103 context.startRendering(); |
| 106 }); | 104 }); |
| 107 | 105 |
| 108 bufferLoader.load(); | 106 bufferLoader.load(); |
| 107 */ | |
|
hongchan
2017/03/09 18:00:13
Remove the commented-out section.
Raymond Toy
2017/03/09 18:09:49
Done.
| |
| 108 Audit.loadFileFromUrl("../Oscillator/oscillator-" + oscType + "-expected.wav ") | |
|
hongchan
2017/03/09 18:00:13
Wrap this line.
Raymond Toy
2017/03/09 18:09:49
Done.
| |
| 109 .then(response => { | |
| 110 return context.decodeAudioData(response); | |
| 111 }) | |
| 112 .then(audioBuffer => { | |
| 113 reference = audioBuffer.getChannelData(0); | |
| 114 generateExponentialOscillatorSweep(context, oscType); | |
| 115 return context.startRendering(); | |
| 116 }) | |
| 117 .then(resultBuffer => { | |
| 118 checkResult(resultBuffer, should, oscType); | |
| 119 }) | |
| 120 .then(() => task.done()); | |
| 109 } | 121 } |
| 110 | 122 |
| 111 function checkResult (event, should, oscType) { | 123 function checkResult (renderedBuffer, should, oscType) { |
| 112 let renderedData = event.renderedBuffer.getChannelData(0); | 124 let renderedData = renderedBuffer.getChannelData(0); |
| 113 // Compute signal to noise ratio between the result and the reference. Also keep track | 125 // Compute signal to noise ratio between the result and the reference. Also keep track |
| 114 // of the max difference (and position). | 126 // of the max difference (and position). |
| 115 | 127 |
| 116 var maxError = -1; | 128 var maxError = -1; |
| 117 var errorPosition = -1; | 129 var errorPosition = -1; |
| 118 var diffCount = 0; | 130 var diffCount = 0; |
| 119 | 131 |
| 120 for (var k = 0; k < renderedData.length; ++k) { | 132 for (var k = 0; k < renderedData.length; ++k) { |
| 121 var diff = renderedData[k] - reference[k]; | 133 var diff = renderedData[k] - reference[k]; |
| 122 noisePower += diff * diff; | 134 noisePower += diff * diff; |
| 123 signalPower += reference[k] * reference[k]; | 135 signalPower += reference[k] * reference[k]; |
| 124 if (Math.abs(diff) > maxError) { | 136 if (Math.abs(diff) > maxError) { |
| 125 maxError = Math.abs(diff); | 137 maxError = Math.abs(diff); |
| 126 errorPosition = k; | 138 errorPosition = k; |
| 127 } | 139 } |
| 128 // The reference file is a 16-bit WAV file, so we will almost never get an exact match | 140 // The reference file is a 16-bit WAV file, so we will almost never get an exact match |
| 129 // between it and the actual floating-point result. | 141 // between it and the actual floating-point result. |
| 130 if (diff > 1/waveScaleFactor) { | 142 if (diff > 0) { |
| 131 diffCount++; | 143 diffCount++; |
| 132 } | 144 } |
| 133 } | 145 } |
| 134 | 146 |
| 135 var snr = calculateSNR(signalPower, noisePower); | 147 var snr = calculateSNR(signalPower, noisePower); |
| 136 should(snr, "SNR") | 148 should(snr, "SNR") |
| 137 .beGreaterThanOrEqualTo(thresholdSNR); | 149 .beGreaterThanOrEqualTo(thresholdSNR); |
| 138 should(maxError * waveScaleFactor, "Maximum difference in ulp (16-bits)") | 150 should(maxError, "Maximum difference") |
| 139 .beLessThanOrEqualTo(thresholdDiff * waveScaleFactor); | 151 .beLessThanOrEqualTo(thresholdDiff); |
| 140 | 152 |
| 141 should(diffCount, | 153 should(diffCount, |
| 142 "Number of differences between actual and expected result out of " | 154 "Number of differences between actual and expected result out of " |
| 143 + renderedData.length + " frames") | 155 + renderedData.length + " frames") |
| 144 .beLessThanOrEqualTo(thresholdDiffCount); | 156 .beLessThanOrEqualTo(thresholdDiffCount); |
| 145 | 157 |
| 146 var filename = "oscillator-" + oscType + "-actual.wav"; | 158 var filename = "oscillator-" + oscType + "-actual.wav"; |
| 147 if (downloadAudioBuffer(event.renderedBuffer, filename)) | 159 if (downloadAudioBuffer(renderedBuffer, filename, true)) |
| 148 should(true, "Saved reference file").message(filename, ""); | 160 should(true, "Saved reference file").message(filename, ""); |
| 149 } | 161 } |
| 150 | 162 |
| 151 function setThresholds(thresholds) { | 163 function setThresholds(thresholds) { |
| 152 thresholdSNR = thresholds.snr; | 164 thresholdSNR = thresholds.snr; |
| 153 thresholdDiff = thresholds.maxDiff / waveScaleFactor; | 165 thresholdDiff = thresholds.maxDiff; |
| 154 thresholdDiffCount = thresholds.diffCount; | 166 thresholdDiffCount = thresholds.diffCount; |
| 155 } | 167 } |
| 156 | 168 |
| 157 function runTest(context, oscType, description, task, should) { | 169 function runTest(context, oscType, description, task, should) { |
| 158 loadReferenceAndRunTest(context, oscType, task, should); | 170 loadReferenceAndRunTest(context, oscType, task, should); |
| 159 } | 171 } |
| 160 | 172 |
| 161 function createNewReference(oscType) { | |
| 162 if (!window.testRunner) | |
| 163 return; | |
| 164 | |
| 165 context = new OfflineAudioContext(1, sampleRate * lengthInSeconds, sampleRa te); | |
| 166 generateExponentialOscillatorSweep(context, oscType); | |
| 167 | |
| 168 context.oncomplete = finishAudioTest; | |
| 169 context.startRendering(); | |
| 170 | |
| 171 testRunner.waitUntilDone(); | |
| 172 } | |
| 173 | |
| 174 return { | 173 return { |
| 175 sampleRate: sampleRate, | 174 sampleRate: sampleRate, |
| 176 lengthInSeconds: lengthInSeconds, | 175 lengthInSeconds: lengthInSeconds, |
| 177 thresholdSNR: thresholdSNR, | 176 thresholdSNR: thresholdSNR, |
| 178 thresholdDiff: thresholdDiff, | 177 thresholdDiff: thresholdDiff, |
| 179 thresholdDiffCount: thresholdDiffCount, | 178 thresholdDiffCount: thresholdDiffCount, |
| 180 waveScaleFactor: waveScaleFactor, | 179 waveScaleFactor: waveScaleFactor, |
| 181 setThresholds: setThresholds, | 180 setThresholds: setThresholds, |
| 182 runTest: runTest, | 181 runTest: runTest, |
| 183 createNewReference: createNewReference, | |
| 184 }; | 182 }; |
| 185 | 183 |
| 186 }()); | 184 }()); |
| OLD | NEW |