|
1 <!DOCTYPE HTML> |
|
2 <html> |
|
3 <head> |
|
4 <title>Test left/right symmetry and block-offset invariance of HRTF panner</title> |
|
5 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> |
|
6 <script type="text/javascript" src="webaudio.js"></script> |
|
7 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> |
|
8 </head> |
|
9 <body> |
|
10 <pre id="test"> |
|
11 <script class="testbody" type="text/javascript"> |
|
12 |
|
13 SimpleTest.waitForExplicitFinish(); |
|
14 |
|
15 const blockSize = 128; |
|
16 const bufferSize = 4096; // > HRTF panner latency |
|
17 |
|
18 var ctx = new AudioContext(); |
|
19 |
|
20 function isChannelSilent(channel) { |
|
21 for (var i = 0; i < channel.length; ++i) { |
|
22 if (channel[i] != 0.0) { |
|
23 return false; |
|
24 } |
|
25 } |
|
26 return true; |
|
27 } |
|
28 |
|
29 function startTest() { |
|
30 var leftPanner = ctx.createPanner(); |
|
31 var rightPanner = ctx.createPanner(); |
|
32 leftPanner.setPosition(-1,0,0); |
|
33 rightPanner.setPosition(1,0,0); |
|
34 |
|
35 // Test that PannerNode processes the signal consistently irrespective of |
|
36 // the offset in the processing block. This is done by inserting a delay of |
|
37 // less than a block size before one panner. |
|
38 const delayTime = 0.7 * blockSize / ctx.sampleRate; |
|
39 var leftDelay = ctx.createDelay(delayTime); |
|
40 leftDelay.delayTime.value = delayTime; |
|
41 leftDelay.connect(leftPanner); |
|
42 // and compensating for the delay after the other. |
|
43 var rightDelay = ctx.createDelay(delayTime); |
|
44 rightDelay.delayTime.value = delayTime; |
|
45 rightPanner.connect(rightDelay); |
|
46 |
|
47 // Feed the panners with a signal having some harmonics to fill the spectrum. |
|
48 var oscillator = ctx.createOscillator(); |
|
49 oscillator.frequency.value = 110; |
|
50 oscillator.type = "sawtooth"; |
|
51 oscillator.connect(leftDelay); |
|
52 oscillator.connect(rightPanner); |
|
53 oscillator.start(0); |
|
54 |
|
55 // Switch the channels on one panner output, and it should match the other. |
|
56 var splitter = ctx.createChannelSplitter(); |
|
57 leftPanner.connect(splitter); |
|
58 var merger = ctx.createChannelMerger(); |
|
59 splitter.connect(merger, 0, 1); |
|
60 splitter.connect(merger, 1, 0); |
|
61 |
|
62 // Invert one signal so that mixing with the other will find the difference. |
|
63 var gain = ctx.createGain(); |
|
64 gain.gain.value = -1.0; |
|
65 merger.connect(gain); |
|
66 |
|
67 var processor = ctx.createScriptProcessor(bufferSize, 2, 0); |
|
68 gain.connect(processor); |
|
69 rightDelay.connect(processor); |
|
70 processor.onaudioprocess = |
|
71 function(e) { |
|
72 compareBuffers(e.inputBuffer, |
|
73 ctx.createBuffer(2, bufferSize, ctx.sampleRate)); |
|
74 e.target.onaudioprocess = null; |
|
75 SimpleTest.finish(); |
|
76 } |
|
77 } |
|
78 |
|
79 function prepareTest() { |
|
80 // A PannerNode will produce no output until it has loaded its HRIR |
|
81 // database. Wait for this to load before starting the test. |
|
82 var processor = ctx.createScriptProcessor(bufferSize, 2, 0); |
|
83 var panner = ctx.createPanner(); |
|
84 panner.connect(processor); |
|
85 var oscillator = ctx.createOscillator(); |
|
86 oscillator.connect(panner); |
|
87 oscillator.start(0); |
|
88 |
|
89 processor.onaudioprocess = |
|
90 function(e) { |
|
91 if (isChannelSilent(e.inputBuffer.getChannelData(0))) |
|
92 return; |
|
93 |
|
94 oscillator.stop(0); |
|
95 panner.disconnect(); |
|
96 e.target.onaudioprocess = null; |
|
97 startTest(); |
|
98 }; |
|
99 } |
|
100 prepareTest(); |
|
101 </script> |
|
102 </pre> |
|
103 </body> |
|
104 </html> |