2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2010 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
34 static void SetSpeakerArrangement(const char *name
, ALfloat SpeakerAngle
[MaxChannels
],
35 enum Channel Speaker2Chan
[MaxChannels
], ALint chans
)
44 if(!ConfigValueStr(NULL
, name
, &str
) && !ConfigValueStr(NULL
, "layout", &str
))
47 layout_str
= strdup(str
);
48 next
= confkey
= layout_str
;
52 next
= strchr(confkey
, ',');
58 } while(isspace(*next
) || *next
== ',');
61 sep
= strchr(confkey
, '=');
62 if(!sep
|| confkey
== sep
)
64 ERR("Malformed speaker key: %s\n", confkey
);
69 while(isspace(*end
) && end
!= confkey
)
73 if(strcmp(confkey
, "fl") == 0 || strcmp(confkey
, "front-left") == 0)
75 else if(strcmp(confkey
, "fr") == 0 || strcmp(confkey
, "front-right") == 0)
77 else if(strcmp(confkey
, "fc") == 0 || strcmp(confkey
, "front-center") == 0)
79 else if(strcmp(confkey
, "bl") == 0 || strcmp(confkey
, "back-left") == 0)
81 else if(strcmp(confkey
, "br") == 0 || strcmp(confkey
, "back-right") == 0)
83 else if(strcmp(confkey
, "bc") == 0 || strcmp(confkey
, "back-center") == 0)
85 else if(strcmp(confkey
, "sl") == 0 || strcmp(confkey
, "side-left") == 0)
87 else if(strcmp(confkey
, "sr") == 0 || strcmp(confkey
, "side-right") == 0)
91 ERR("Unknown speaker for %s: \"%s\"\n", name
, confkey
);
99 for(i
= 0;i
< chans
;i
++)
101 if(Speaker2Chan
[i
] == val
)
103 long angle
= strtol(sep
, NULL
, 10);
104 if(angle
>= -180 && angle
<= 180)
105 SpeakerAngle
[i
] = angle
* F_PI
/180.0f
;
107 ERR("Invalid angle for speaker \"%s\": %ld\n", confkey
, angle
);
115 for(i
= 0;i
< chans
;i
++)
120 for(i2
= i
+1;i2
< chans
;i2
++)
122 if(SpeakerAngle
[i2
] < SpeakerAngle
[min
])
131 tmpf
= SpeakerAngle
[i
];
132 SpeakerAngle
[i
] = SpeakerAngle
[min
];
133 SpeakerAngle
[min
] = tmpf
;
135 tmpc
= Speaker2Chan
[i
];
136 Speaker2Chan
[i
] = Speaker2Chan
[min
];
137 Speaker2Chan
[min
] = tmpc
;
146 * Sets channel gains based on a given source's angle and its half-width. The
147 * angle and hwidth parameters are in radians.
149 ALvoid
ComputeAngleGains(const ALCdevice
*device
, ALfloat angle
, ALfloat hwidth
, ALfloat ingain
, ALfloat
*gains
)
151 ALfloat tmpgains
[MaxChannels
] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
};
152 enum Channel Speaker2Chan
[MaxChannels
];
153 ALfloat SpeakerAngle
[MaxChannels
];
154 ALfloat langle
, rangle
;
158 for(i
= 0;i
< device
->NumChan
;i
++)
159 Speaker2Chan
[i
] = device
->Speaker2Chan
[i
];
160 for(i
= 0;i
< device
->NumChan
;i
++)
161 SpeakerAngle
[i
] = device
->SpeakerAngle
[i
];
163 /* Some easy special-cases first... */
164 if(device
->NumChan
== 1 || hwidth
>= F_PI
)
166 /* Full coverage for all speakers. */
167 for(i
= 0;i
< device
->NumChan
;i
++)
169 enum Channel chan
= Speaker2Chan
[i
];
170 gains
[chan
] = ingain
;
176 /* Infinitely small sound point. */
177 for(i
= 0;i
< device
->NumChan
-1;i
++)
179 if(angle
>= SpeakerAngle
[i
] && angle
< SpeakerAngle
[i
+1])
181 /* Sound is between speakers i and i+1 */
182 a
= (angle
-SpeakerAngle
[i
]) /
183 (SpeakerAngle
[i
+1]-SpeakerAngle
[i
]);
184 gains
[Speaker2Chan
[i
]] = sqrtf(1.0f
-a
) * ingain
;
185 gains
[Speaker2Chan
[i
+1]] = sqrtf( a
) * ingain
;
189 /* Sound is between last and first speakers */
190 if(angle
< SpeakerAngle
[0])
192 a
= (angle
-SpeakerAngle
[i
]) /
193 (F_PI
*2.0f
+ SpeakerAngle
[0]-SpeakerAngle
[i
]);
194 gains
[Speaker2Chan
[i
]] = sqrtf(1.0f
-a
) * ingain
;
195 gains
[Speaker2Chan
[0]] = sqrtf( a
) * ingain
;
199 if(fabsf(angle
)+hwidth
> F_PI
)
201 /* The coverage area would go outside of -pi...+pi. Instead, rotate the
202 * speaker angles so it would be as if angle=0, and keep them wrapped
203 * within -pi...+pi. */
204 for(i
= 0;i
< device
->NumChan
;i
++)
206 SpeakerAngle
[i
] -= angle
;
207 if(SpeakerAngle
[i
] > F_PI
)
208 SpeakerAngle
[i
] -= F_PI
*2.0f
;
209 else if(SpeakerAngle
[i
] < -F_PI
)
210 SpeakerAngle
[i
] += F_PI
*2.0f
;
214 /* The speaker angles are expected to be in ascending order. There
215 * should be a better way to resort the lists... */
216 for(i
= 0;i
< device
->NumChan
-1;i
++)
221 for(j
= i
+1;j
< device
->NumChan
;j
++)
223 if(SpeakerAngle
[j
] < SpeakerAngle
[min
])
232 tmpf
= SpeakerAngle
[i
];
233 SpeakerAngle
[i
] = SpeakerAngle
[min
];
234 SpeakerAngle
[min
] = tmpf
;
236 tmpc
= Speaker2Chan
[i
];
237 Speaker2Chan
[i
] = Speaker2Chan
[min
];
238 Speaker2Chan
[min
] = tmpc
;
242 langle
= angle
- hwidth
;
243 rangle
= angle
+ hwidth
;
248 ALuint last
= device
->NumChan
-1;
249 enum Channel chan
= Speaker2Chan
[i
];
251 if(SpeakerAngle
[i
] >= langle
&& SpeakerAngle
[i
] <= rangle
)
253 tmpgains
[chan
] = 1.0f
;
257 if(SpeakerAngle
[i
] < langle
&& SpeakerAngle
[i
+1] > langle
)
259 a
= (langle
-SpeakerAngle
[i
]) /
260 (SpeakerAngle
[i
+1]-SpeakerAngle
[i
]);
261 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, 1.0f
-a
);
263 if(SpeakerAngle
[i
] > rangle
)
265 a
= (F_PI
*2.0f
+ rangle
-SpeakerAngle
[last
]) /
266 (F_PI
*2.0f
+ SpeakerAngle
[i
]-SpeakerAngle
[last
]);
267 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, a
);
269 else if(SpeakerAngle
[last
] < rangle
)
271 a
= (rangle
-SpeakerAngle
[last
]) /
272 (F_PI
*2.0f
+ SpeakerAngle
[i
]-SpeakerAngle
[last
]);
273 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, a
);
277 for(i
= 1;i
< device
->NumChan
-1;i
++)
279 enum Channel chan
= Speaker2Chan
[i
];
280 if(SpeakerAngle
[i
] >= langle
&& SpeakerAngle
[i
] <= rangle
)
282 tmpgains
[chan
] = 1.0f
;
286 if(SpeakerAngle
[i
] < langle
&& SpeakerAngle
[i
+1] > langle
)
288 a
= (langle
-SpeakerAngle
[i
]) /
289 (SpeakerAngle
[i
+1]-SpeakerAngle
[i
]);
290 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, 1.0f
-a
);
292 if(SpeakerAngle
[i
] > rangle
&& SpeakerAngle
[i
-1] < rangle
)
294 a
= (rangle
-SpeakerAngle
[i
-1]) /
295 (SpeakerAngle
[i
]-SpeakerAngle
[i
-1]);
296 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, a
);
301 i
= device
->NumChan
-1;
303 enum Channel chan
= Speaker2Chan
[i
];
304 if(SpeakerAngle
[i
] >= langle
&& SpeakerAngle
[i
] <= rangle
)
306 tmpgains
[Speaker2Chan
[i
]] = 1.0f
;
309 if(SpeakerAngle
[i
] > rangle
&& SpeakerAngle
[i
-1] < rangle
)
311 a
= (rangle
-SpeakerAngle
[i
-1]) /
312 (SpeakerAngle
[i
]-SpeakerAngle
[i
-1]);
313 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, a
);
315 if(SpeakerAngle
[i
] < langle
)
317 a
= (langle
-SpeakerAngle
[i
]) /
318 (F_PI
*2.0f
+ SpeakerAngle
[0]-SpeakerAngle
[i
]);
319 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, 1.0f
-a
);
321 else if(SpeakerAngle
[0] > langle
)
323 a
= (F_PI
*2.0f
+ langle
-SpeakerAngle
[i
]) /
324 (F_PI
*2.0f
+ SpeakerAngle
[0]-SpeakerAngle
[i
]);
325 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, 1.0f
-a
);
329 for(i
= 0;i
< device
->NumChan
;i
++)
331 enum Channel chan
= device
->Speaker2Chan
[i
];
332 gains
[chan
] = sqrtf(tmpgains
[chan
]) * ingain
;
337 ALvoid
aluInitPanning(ALCdevice
*Device
)
339 const char *layoutname
= NULL
;
340 enum Channel
*Speaker2Chan
;
341 ALfloat
*SpeakerAngle
;
343 Speaker2Chan
= Device
->Speaker2Chan
;
344 SpeakerAngle
= Device
->SpeakerAngle
;
345 switch(Device
->FmtChans
)
349 Speaker2Chan
[0] = FrontCenter
;
350 SpeakerAngle
[0] = F_PI
/180.0f
* 0.0f
;
356 Speaker2Chan
[0] = FrontLeft
;
357 Speaker2Chan
[1] = FrontRight
;
358 SpeakerAngle
[0] = F_PI
/180.0f
* -90.0f
;
359 SpeakerAngle
[1] = F_PI
/180.0f
* 90.0f
;
360 layoutname
= "layout_stereo";
365 Speaker2Chan
[0] = BackLeft
;
366 Speaker2Chan
[1] = FrontLeft
;
367 Speaker2Chan
[2] = FrontRight
;
368 Speaker2Chan
[3] = BackRight
;
369 SpeakerAngle
[0] = F_PI
/180.0f
* -135.0f
;
370 SpeakerAngle
[1] = F_PI
/180.0f
* -45.0f
;
371 SpeakerAngle
[2] = F_PI
/180.0f
* 45.0f
;
372 SpeakerAngle
[3] = F_PI
/180.0f
* 135.0f
;
373 layoutname
= "layout_quad";
378 Speaker2Chan
[0] = BackLeft
;
379 Speaker2Chan
[1] = FrontLeft
;
380 Speaker2Chan
[2] = FrontCenter
;
381 Speaker2Chan
[3] = FrontRight
;
382 Speaker2Chan
[4] = BackRight
;
383 SpeakerAngle
[0] = F_PI
/180.0f
* -110.0f
;
384 SpeakerAngle
[1] = F_PI
/180.0f
* -30.0f
;
385 SpeakerAngle
[2] = F_PI
/180.0f
* 0.0f
;
386 SpeakerAngle
[3] = F_PI
/180.0f
* 30.0f
;
387 SpeakerAngle
[4] = F_PI
/180.0f
* 110.0f
;
388 layoutname
= "layout_surround51";
393 Speaker2Chan
[0] = SideLeft
;
394 Speaker2Chan
[1] = FrontLeft
;
395 Speaker2Chan
[2] = FrontCenter
;
396 Speaker2Chan
[3] = FrontRight
;
397 Speaker2Chan
[4] = SideRight
;
398 SpeakerAngle
[0] = F_PI
/180.0f
* -90.0f
;
399 SpeakerAngle
[1] = F_PI
/180.0f
* -30.0f
;
400 SpeakerAngle
[2] = F_PI
/180.0f
* 0.0f
;
401 SpeakerAngle
[3] = F_PI
/180.0f
* 30.0f
;
402 SpeakerAngle
[4] = F_PI
/180.0f
* 90.0f
;
403 layoutname
= "layout_side51";
408 Speaker2Chan
[0] = SideLeft
;
409 Speaker2Chan
[1] = FrontLeft
;
410 Speaker2Chan
[2] = FrontCenter
;
411 Speaker2Chan
[3] = FrontRight
;
412 Speaker2Chan
[4] = SideRight
;
413 Speaker2Chan
[5] = BackCenter
;
414 SpeakerAngle
[0] = F_PI
/180.0f
* -90.0f
;
415 SpeakerAngle
[1] = F_PI
/180.0f
* -30.0f
;
416 SpeakerAngle
[2] = F_PI
/180.0f
* 0.0f
;
417 SpeakerAngle
[3] = F_PI
/180.0f
* 30.0f
;
418 SpeakerAngle
[4] = F_PI
/180.0f
* 90.0f
;
419 SpeakerAngle
[5] = F_PI
/180.0f
* 180.0f
;
420 layoutname
= "layout_surround61";
425 Speaker2Chan
[0] = BackLeft
;
426 Speaker2Chan
[1] = SideLeft
;
427 Speaker2Chan
[2] = FrontLeft
;
428 Speaker2Chan
[3] = FrontCenter
;
429 Speaker2Chan
[4] = FrontRight
;
430 Speaker2Chan
[5] = SideRight
;
431 Speaker2Chan
[6] = BackRight
;
432 SpeakerAngle
[0] = F_PI
/180.0f
* -150.0f
;
433 SpeakerAngle
[1] = F_PI
/180.0f
* -90.0f
;
434 SpeakerAngle
[2] = F_PI
/180.0f
* -30.0f
;
435 SpeakerAngle
[3] = F_PI
/180.0f
* 0.0f
;
436 SpeakerAngle
[4] = F_PI
/180.0f
* 30.0f
;
437 SpeakerAngle
[5] = F_PI
/180.0f
* 90.0f
;
438 SpeakerAngle
[6] = F_PI
/180.0f
* 150.0f
;
439 layoutname
= "layout_surround71";
442 if(layoutname
&& Device
->Type
!= Loopback
)
443 SetSpeakerArrangement(layoutname
, SpeakerAngle
, Speaker2Chan
, Device
->NumChan
);