OLD | NEW |
1 var StereoPannerTest = (function () { | 1 var StereoPannerTest = (function() { |
2 | 2 |
3 // Constants | 3 // Constants |
4 var PI_OVER_TWO = Math.PI * 0.5; | 4 let PI_OVER_TWO = Math.PI * 0.5; |
5 | 5 |
6 var gSampleRate = 44100; | 6 let gSampleRate = 44100; |
7 | 7 |
8 // Time step when each panner node starts. | 8 // Time step when each panner node starts. |
9 var gTimeStep = 0.001; | 9 let gTimeStep = 0.001; |
10 | 10 |
11 // How many panner nodes to create for the test | 11 // How many panner nodes to create for the test |
12 var gNodesToCreate = 100; | 12 let gNodesToCreate = 100; |
13 | 13 |
14 // Total render length for all of our nodes. | 14 // Total render length for all of our nodes. |
15 var gRenderLength = gTimeStep * (gNodesToCreate + 1) + gSampleRate; | 15 let gRenderLength = gTimeStep * (gNodesToCreate + 1) + gSampleRate; |
16 | 16 |
17 // Calculates channel gains based on equal power panning model. | 17 // Calculates channel gains based on equal power panning model. |
18 // See: http://webaudio.github.io/web-audio-api/#panning-algorithm | 18 // See: http://webaudio.github.io/web-audio-api/#panning-algorithm |
19 function getChannelGain(pan, numberOfChannels) { | 19 function getChannelGain(pan, numberOfChannels) { |
20 // The internal panning clips the pan value between -1, 1. | 20 // The internal panning clips the pan value between -1, 1. |
21 pan = Math.min(Math.max(pan, -1), 1); | 21 pan = Math.min(Math.max(pan, -1), 1); |
22 var gainL, gainR; | 22 let gainL, gainR; |
23 // Consider number of channels and pan value's polarity. | 23 // Consider number of channels and pan value's polarity. |
24 if (numberOfChannels == 1) { | 24 if (numberOfChannels == 1) { |
25 var panRadian = (pan * 0.5 + 0.5) * PI_OVER_TWO; | 25 let panRadian = (pan * 0.5 + 0.5) * PI_OVER_TWO; |
26 gainL = Math.cos(panRadian); | 26 gainL = Math.cos(panRadian); |
27 gainR = Math.sin(panRadian); | 27 gainR = Math.sin(panRadian); |
28 } else { | 28 } else { |
29 var panRadian = (pan <= 0 ? pan + 1 : pan) * PI_OVER_TWO; | 29 let panRadian = (pan <= 0 ? pan + 1 : pan) * PI_OVER_TWO; |
30 if (pan <= 0) { | 30 if (pan <= 0) { |
31 gainL = 1 + Math.cos(panRadian); | 31 gainL = 1 + Math.cos(panRadian); |
32 gainR = Math.sin(panRadian); | 32 gainR = Math.sin(panRadian); |
33 } else { | 33 } else { |
34 gainL = Math.cos(panRadian); | 34 gainL = Math.cos(panRadian); |
35 gainR = 1 + Math.sin(panRadian); | 35 gainR = 1 + Math.sin(panRadian); |
36 } | 36 } |
37 } | 37 } |
38 return { | 38 return {gainL: gainL, gainR: gainR}; |
39 gainL: gainL, | |
40 gainR: gainR | |
41 }; | |
42 } | 39 } |
43 | 40 |
44 | 41 |
45 /** | 42 /** |
46 * Test implementation class. | 43 * Test implementation class. |
47 * @param {Object} options Test options | 44 * @param {Object} options Test options |
48 * @param {Object} options.description Test description | 45 * @param {Object} options.description Test description |
49 * @param {Object} options.numberOfInputChannels Number of input channels | 46 * @param {Object} options.numberOfInputChannels Number of input channels |
50 */ | 47 */ |
51 function Test(should, options) { | 48 function Test(should, options) { |
52 | |
53 // Primary test flag. | 49 // Primary test flag. |
54 this.success = true; | 50 this.success = true; |
55 | 51 |
56 this.should = should; | 52 this.should = should; |
57 this.context = null; | 53 this.context = null; |
58 this.prefix = options.prefix; | 54 this.prefix = options.prefix; |
59 this.numberOfInputChannels = (options.numberOfInputChannels || 1); | 55 this.numberOfInputChannels = (options.numberOfInputChannels || 1); |
60 switch (this.numberOfInputChannels) { | 56 switch (this.numberOfInputChannels) { |
61 case 1: | 57 case 1: |
62 this.description = 'Test for mono input'; | 58 this.description = 'Test for mono input'; |
(...skipping 20 matching lines...) Expand all Loading... |
83 // to 0 to make the test fail to see what the actual error is. | 79 // to 0 to make the test fail to see what the actual error is. |
84 this.maxAllowedError = 1.3e-6; | 80 this.maxAllowedError = 1.3e-6; |
85 | 81 |
86 // Max (absolute) error and the index of the maxima for the left | 82 // Max (absolute) error and the index of the maxima for the left |
87 // and right channels. | 83 // and right channels. |
88 this.maxErrorL = 0; | 84 this.maxErrorL = 0; |
89 this.maxErrorR = 0; | 85 this.maxErrorR = 0; |
90 this.maxErrorIndexL = 0; | 86 this.maxErrorIndexL = 0; |
91 this.maxErrorIndexR = 0; | 87 this.maxErrorIndexR = 0; |
92 | 88 |
93 // The maximum value to use for panner pan value. The value will range from
-panLimit to | 89 // The maximum value to use for panner pan value. The value will range from |
94 // +panLimit. | 90 // -panLimit to +panLimit. |
95 this.panLimit = 1.0625; | 91 this.panLimit = 1.0625; |
96 } | 92 } |
97 | 93 |
98 | 94 |
99 Test.prototype.init = function () { | 95 Test.prototype.init = function() { |
100 this.context = new OfflineAudioContext(2, gRenderLength, gSampleRate); | 96 this.context = new OfflineAudioContext(2, gRenderLength, gSampleRate); |
101 }; | 97 }; |
102 | 98 |
103 // Prepare an audio graph for testing. Create multiple impulse generators and | 99 // Prepare an audio graph for testing. Create multiple impulse generators and |
104 // panner nodes, then play them sequentially while varying the pan position. | 100 // panner nodes, then play them sequentially while varying the pan position. |
105 Test.prototype.prepare = function () { | 101 Test.prototype.prepare = function() { |
106 var impulse; | 102 let impulse; |
107 var impulseLength = Math.round(gTimeStep * gSampleRate); | 103 let impulseLength = Math.round(gTimeStep * gSampleRate); |
108 var sources = []; | 104 let sources = []; |
109 var panners = []; | 105 let panners = []; |
110 | 106 |
111 // Moves the pan value for each panner by pan step unit from -2 to 2. | 107 // Moves the pan value for each panner by pan step unit from -2 to 2. |
112 // This is to check if the internal panning value is clipped properly. | 108 // This is to check if the internal panning value is clipped properly. |
113 var panStep = (2 * this.panLimit) / (gNodesToCreate - 1); | 109 let panStep = (2 * this.panLimit) / (gNodesToCreate - 1); |
114 | 110 |
115 if (this.numberOfInputChannels === 1) { | 111 if (this.numberOfInputChannels === 1) { |
116 impulse = createImpulseBuffer(this.context, impulseLength); | 112 impulse = createImpulseBuffer(this.context, impulseLength); |
117 } else { | 113 } else { |
118 impulse = createStereoImpulseBuffer(this.context, impulseLength); | 114 impulse = createStereoImpulseBuffer(this.context, impulseLength); |
119 } | 115 } |
120 | 116 |
121 for (var i = 0; i < gNodesToCreate; i++) { | 117 for (let i = 0; i < gNodesToCreate; i++) { |
122 sources[i] = this.context.createBufferSource(); | 118 sources[i] = this.context.createBufferSource(); |
123 panners[i] = this.context.createStereoPanner(); | 119 panners[i] = this.context.createStereoPanner(); |
124 sources[i].connect(panners[i]); | 120 sources[i].connect(panners[i]); |
125 panners[i].connect(this.context.destination); | 121 panners[i].connect(this.context.destination); |
126 sources[i].buffer = impulse; | 122 sources[i].buffer = impulse; |
127 panners[i].pan.value = this.panPositions[i] = panStep * i - this.panLimit; | 123 panners[i].pan.value = this.panPositions[i] = panStep * i - this.panLimit; |
128 | 124 |
129 // Store the onset time position of impulse. | 125 // Store the onset time position of impulse. |
130 this.onsets[i] = gTimeStep * i; | 126 this.onsets[i] = gTimeStep * i; |
131 | 127 |
132 sources[i].start(this.onsets[i]); | 128 sources[i].start(this.onsets[i]); |
133 } | 129 } |
134 }; | 130 }; |
135 | 131 |
136 | 132 |
137 Test.prototype.verify = function () { | 133 Test.prototype.verify = function() { |
138 var chanL = this.renderedBufferL; | 134 let chanL = this.renderedBufferL; |
139 var chanR = this.renderedBufferR; | 135 let chanR = this.renderedBufferR; |
140 for (var i = 0; i < chanL.length; i++) { | 136 for (let i = 0; i < chanL.length; i++) { |
141 // Left and right channels must start at the same instant. | 137 // Left and right channels must start at the same instant. |
142 if (chanL[i] !== 0 || chanR[i] !== 0) { | 138 if (chanL[i] !== 0 || chanR[i] !== 0) { |
143 | |
144 // Get amount of error between actual and expected gain. | 139 // Get amount of error between actual and expected gain. |
145 var expected = getChannelGain( | 140 let expected = getChannelGain( |
146 this.panPositions[this.impulseIndex], | 141 this.panPositions[this.impulseIndex], this.numberOfInputChannels); |
147 this.numberOfInputChannels | 142 let errorL = Math.abs(chanL[i] - expected.gainL); |
148 ); | 143 let errorR = Math.abs(chanR[i] - expected.gainR); |
149 var errorL = Math.abs(chanL[i] - expected.gainL); | |
150 var errorR = Math.abs(chanR[i] - expected.gainR); | |
151 | 144 |
152 if (errorL > this.maxErrorL) { | 145 if (errorL > this.maxErrorL) { |
153 this.maxErrorL = errorL; | 146 this.maxErrorL = errorL; |
154 this.maxErrorIndexL = this.impulseIndex; | 147 this.maxErrorIndexL = this.impulseIndex; |
155 } | 148 } |
156 if (errorR > this.maxErrorR) { | 149 if (errorR > this.maxErrorR) { |
157 this.maxErrorR = errorR; | 150 this.maxErrorR = errorR; |
158 this.maxErrorIndexR = this.impulseIndex; | 151 this.maxErrorIndexR = this.impulseIndex; |
159 } | 152 } |
160 | 153 |
161 // Keep track of the impulses that didn't show up where we expected | 154 // Keep track of the impulses that didn't show up where we expected |
162 // them to be. | 155 // them to be. |
163 var expectedOffset = timeToSampleFrame( | 156 let expectedOffset = |
164 this.onsets[this.impulseIndex], | 157 timeToSampleFrame(this.onsets[this.impulseIndex], gSampleRate); |
165 gSampleRate | |
166 ); | |
167 if (i != expectedOffset) { | 158 if (i != expectedOffset) { |
168 this.errors.push({ | 159 this.errors.push({actual: i, expected: expectedOffset}); |
169 actual: i, | |
170 expected: expectedOffset | |
171 }); | |
172 } | 160 } |
173 | 161 |
174 this.impulseIndex++; | 162 this.impulseIndex++; |
175 } | 163 } |
176 } | 164 } |
177 }; | 165 }; |
178 | 166 |
179 | 167 |
180 Test.prototype.showResult = function () { | 168 Test.prototype.showResult = function() { |
181 this.should(this.impulseIndex, this.prefix + "Number of impulses found") | 169 this.should(this.impulseIndex, this.prefix + 'Number of impulses found') |
182 .beEqualTo(gNodesToCreate); | 170 .beEqualTo(gNodesToCreate); |
183 | 171 |
184 this.should(this.errors.length, this.prefix + "Number of impulse at the wron
g offset") | 172 this.should( |
185 .beEqualTo(0); | 173 this.errors.length, |
| 174 this.prefix + 'Number of impulse at the wrong offset') |
| 175 .beEqualTo(0); |
186 | 176 |
187 this.should(this.maxErrorL, this.prefix + "Left channel error magnitude") | 177 this.should(this.maxErrorL, this.prefix + 'Left channel error magnitude') |
188 .beLessThanOrEqualTo(this.maxAllowedError); | 178 .beLessThanOrEqualTo(this.maxAllowedError); |
189 | 179 |
190 this.should(this.maxErrorR, this.prefix + "Right channel error magnitude") | 180 this.should(this.maxErrorR, this.prefix + 'Right channel error magnitude') |
191 .beLessThanOrEqualTo(this.maxAllowedError); | 181 .beLessThanOrEqualTo(this.maxAllowedError); |
192 }; | 182 }; |
193 | 183 |
194 Test.prototype.run = function () { | 184 Test.prototype.run = function() { |
195 | 185 |
196 this.init(); | 186 this.init(); |
197 this.prepare(); | 187 this.prepare(); |
198 | 188 |
199 return this.context.startRendering() | 189 return this.context.startRendering().then(renderedBuffer => { |
200 .then(renderedBuffer => { | 190 this.renderedBufferL = renderedBuffer.getChannelData(0); |
201 this.renderedBufferL = renderedBuffer.getChannelData(0); | 191 this.renderedBufferR = renderedBuffer.getChannelData(1); |
202 this.renderedBufferR = renderedBuffer.getChannelData(1); | 192 this.verify(); |
203 this.verify(); | 193 this.showResult(); |
204 this.showResult(); | 194 }); |
205 }); | |
206 }; | 195 }; |
207 | 196 |
208 return { | 197 return { |
209 create: function (should, options) { | 198 create: function(should, options) { |
210 return new Test(should, options); | 199 return new Test(should, options); |
211 } | 200 } |
212 }; | 201 }; |
213 | 202 |
214 })(); | 203 })(); |
215 | |
OLD | NEW |