test_periodicWaveBandLimiting.html (3211B)
1 <!DOCTYPE html> 2 <title>Test effect of band limiting on PeriodicWave signals</title> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 <script> 6 const sampleRate = 48000; 7 const bufferSize = 12800; 8 const epsilon = 0.01; 9 10 // "All implementations must support arrays up to at least 8192", but the 11 // linear interpolation of the current implementation distorts the higher 12 // frequency components too much to pass this test. 13 const frequencyIndexMax = 200; 14 15 // A set of oscillators are created near the Nyquist frequency. 16 // These are factors giving each oscillator frequency relative to the Nyquist. 17 // The first is an octave below Nyquist and the last is just above. 18 const OCTAVE_BELOW = 0; 19 const HALF_BELOW = 1; 20 const NEAR_BELOW = 2; 21 const ABOVE = 3; 22 const oscillatorFactors = [0.5, Math.sqrt(0.5), 0.99, 1.01]; 23 const oscillatorCount = oscillatorFactors.length; 24 25 // Return magnitude relative to unit sine wave 26 function magnitude(array) { 27 var mag = 0 28 for (var i = 0; i < array.length; ++i) { 29 let sample = array[i]; 30 mag += sample * sample; 31 } 32 return Math.sqrt(2 * mag / array.length); 33 } 34 35 function test_frequency_index(frequencyIndex) { 36 37 var context = 38 new OfflineAudioContext(oscillatorCount, bufferSize, sampleRate); 39 40 var merger = context.createChannelMerger(oscillatorCount); 41 merger.connect(context.destination); 42 43 var real = new Float32Array(frequencyIndex + 1); 44 real[frequencyIndex] = 1; 45 var image = new Float32Array(real.length); 46 var wave = context.createPeriodicWave(real, image); 47 48 for (var i = 0; i < oscillatorCount; ++i) { 49 var oscillator = context.createOscillator(); 50 oscillator.frequency.value = 51 oscillatorFactors[i] * sampleRate / (2 * frequencyIndex); 52 oscillator.connect(merger, 0, i); 53 oscillator.setPeriodicWave(wave); 54 oscillator.start(0); 55 } 56 57 return context.startRendering(). 58 then((buffer) => { 59 assert_equals(buffer.numberOfChannels, oscillatorCount); 60 var magnitudes = []; 61 for (var i = 0; i < oscillatorCount; ++i) { 62 magnitudes[i] = magnitude(buffer.getChannelData(i)); 63 } 64 // Unaffected by band-limiting one octave below Nyquist. 65 assert_approx_equals(magnitudes[OCTAVE_BELOW], 1, epsilon, 66 "magnitude with frequency octave below Nyquist"); 67 // Still at least half the amplitude at half octave below Nyquist. 68 assert_greater_than(magnitudes[HALF_BELOW], 0.5 * (1 - epsilon), 69 "magnitude with frequency half octave below Nyquist"); 70 // Approaching zero or zero near Nyquist. 71 assert_less_than(magnitudes[NEAR_BELOW], 0.1, 72 "magnitude with frequency near Nyquist"); 73 assert_equals(magnitudes[ABOVE], 0, 74 "magnitude with frequency above Nyquist"); 75 }); 76 } 77 78 // The 5/4 ratio with rounding up provides sampling across a range of 79 // octaves and offsets within octaves. 80 for (var frequencyIndex = 1; 81 frequencyIndex < frequencyIndexMax; 82 frequencyIndex = Math.floor((5 * frequencyIndex + 3) / 4)) { 83 promise_test(test_frequency_index.bind(null, frequencyIndex), 84 "Frequency " + frequencyIndex); 85 } 86 </script>