OLD | NEW |
1 <!doctype html> | 1 <!doctype html> |
2 <html> | 2 <html> |
3 <head> | 3 <head> |
4 <title>Test Custom Oscillator at Very Low Frequency</title> | 4 <title>Test Custom Oscillator at Very Low Frequency</title> |
5 <script src="../../resources/testharness.js"></script> | 5 <script src="../../resources/testharness.js"></script> |
6 <script src="../../resources/testharnessreport.js"></script> | 6 <script src="../../resources/testharnessreport.js"></script> |
7 <script src="../resources/audit-util.js"></script> | 7 <script src="../resources/audit-util.js"></script> |
8 <script src="../resources/audio-testing.js"></script> | 8 <script src="../resources/audit.js"></script> |
9 </head> | 9 </head> |
10 | 10 |
11 <body> | 11 <body> |
12 <script> | 12 <script> |
13 // Create a custom oscillator and verify that the parts of a periodic wave
that should be | 13 // Create a custom oscillator and verify that the parts of a periodic wave
that should be |
14 // ignored really are ignored. | 14 // ignored really are ignored. |
15 | 15 |
16 var sampleRate = 48000; | 16 var sampleRate = 48000; |
17 | 17 |
18 // The desired frequency of the oscillator. The value to be used depends
on the | 18 // The desired frequency of the oscillator. The value to be used depends
on the |
19 // implementation of the PeriodicWave and should be less than then lowest
fundamental | 19 // implementation of the PeriodicWave and should be less than then lowest
fundamental |
20 // frequency. The lowest frequency is the Nyquist frequency divided by the
max number of | 20 // frequency. The lowest frequency is the Nyquist frequency divided by the
max number of |
21 // coefficients used for the FFT. In the current implementation, the max n
umber of | 21 // coefficients used for the FFT. In the current implementation, the max n
umber of |
22 // coefficients is 2048 (for a sample rate of 48 kHz) so the lowest freque
ncy is 24000/2048 = | 22 // coefficients is 2048 (for a sample rate of 48 kHz) so the lowest freque
ncy is 24000/2048 = |
23 // 11.78 Hz. | 23 // 11.78 Hz. |
24 var desiredFrequencyHz = 1; | 24 var desiredFrequencyHz = 1; |
25 | 25 |
26 // Minimum allowed SNR between the actual oscillator and the expected resu
lt. Experimentally | 26 // Minimum allowed SNR between the actual oscillator and the expected resu
lt. Experimentally |
27 // determined. | 27 // determined. |
28 var snrThreshold = 130; | 28 var snrThreshold = 130; |
29 | 29 |
30 var context; | 30 var context; |
31 var osc; | 31 var osc; |
32 var actual; | 32 var actual; |
33 | 33 |
34 var audit = Audit.createTaskRunner(); | 34 var audit = Audit.createTaskRunner(); |
35 | 35 |
36 // Compute the SNR between the actual result and expected cosine wave | 36 // Compute the SNR between the actual result and expected cosine wave |
37 function checkCosineResult(result, freq, sampleRate) { | 37 function checkCosineResult(should, result, freq, sampleRate) { |
38 var signal = 0; | 38 var signal = 0; |
39 var noise = 0; | 39 var noise = 0; |
40 var omega = 2 * Math.PI * freq / sampleRate; | 40 var omega = 2 * Math.PI * freq / sampleRate; |
41 | 41 |
42 actual = result.getChannelData(0); | 42 actual = result.getChannelData(0); |
43 | 43 |
44 for (var k = 0; k < actual.length; ++k) { | 44 for (var k = 0; k < actual.length; ++k) { |
45 var x = Math.cos(omega * k); | 45 var x = Math.cos(omega * k); |
46 var diff = x - actual[k]; | 46 var diff = x - actual[k]; |
47 signal += x * x; | 47 signal += x * x; |
48 noise += diff * diff; | 48 noise += diff * diff; |
49 } | 49 } |
50 | 50 |
51 var snr = 10 * Math.log10(signal / noise); | 51 var snr = 10 * Math.log10(signal / noise); |
52 | 52 |
53 Should("SNR of " + desiredFrequencyHz + " Hz sine wave", snr, { | 53 should(snr, "SNR of " + desiredFrequencyHz + " Hz sine wave") |
54 brief: true | 54 .beGreaterThanOrEqualTo(snrThreshold); |
55 }).beGreaterThanOrEqualTo(snrThreshold); | |
56 testPassed("PeriodicWave coefficients that must be ignored were correctl
y ignored."); | |
57 } | 55 } |
58 | 56 |
59 function runTest() { | 57 audit.define("low-freq-oscillator", (task, should) => { |
60 context = new OfflineAudioContext(1, sampleRate, sampleRate); | 58 context = new OfflineAudioContext(1, sampleRate, sampleRate); |
61 osc = context.createOscillator(); | 59 osc = context.createOscillator(); |
62 | 60 |
63 // Create the custom oscillator. For simplicity of testing, we use just
a cosine wave, but | 61 // Create the custom oscillator. For simplicity of testing, we use just
a cosine wave, but |
64 // the initial elements of the real and imaginary parts are explicitly s
et to non-zero to | 62 // the initial elements of the real and imaginary parts are explicitly s
et to non-zero to |
65 // test that they are ignored. | 63 // test that they are ignored. |
66 var r = new Float32Array(2); | 64 var r = new Float32Array(2); |
67 var i = new Float32Array(2); | 65 var i = new Float32Array(2); |
68 r[0] = 1; // DC component to be ignored | 66 r[0] = 1; // DC component to be ignored |
69 r[1] = 1; // Fundamental | 67 r[1] = 1; // Fundamental |
70 i[0] = 1; // Sine term that doesn't actually exist in a Fourier series | 68 i[0] = 1; // Sine term that doesn't actually exist in a Fourier series |
71 i[1] = 0; | 69 i[1] = 0; |
72 var wave = context.createPeriodicWave(r, i); | 70 var wave = context.createPeriodicWave(r, i); |
73 | 71 |
74 osc.setPeriodicWave(wave); | 72 osc.setPeriodicWave(wave); |
75 osc.frequency.value = desiredFrequencyHz; | 73 osc.frequency.value = desiredFrequencyHz; |
76 osc.connect(context.destination); | 74 osc.connect(context.destination); |
77 osc.start(); | 75 osc.start(); |
78 context.startRendering().then(function (buffer) { | 76 context.startRendering().then(function (buffer) { |
79 checkCosineResult(buffer, desiredFrequencyHz, sampleRate); | 77 checkCosineResult(should, buffer, desiredFrequencyHz, sampleRate); |
80 }); | 78 }) |
81 }; | 79 .then(() => task.done()); |
| 80 }); |
82 | 81 |
83 runTest(); | 82 audit.run(); |
84 </script> | 83 </script> |
85 </body> | 84 </body> |
86 </html> | 85 </html> |
OLD | NEW |