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. */
208 while(i
< device
->NumChan
&& device
->SpeakerAngle
[i
]-angle
< -F_PI
)
210 for(done
= 0;i
< device
->NumChan
;done
++)
212 SpeakerAngle
[done
] = device
->SpeakerAngle
[i
]-angle
;
213 Speaker2Chan
[done
] = device
->Speaker2Chan
[i
];
216 for(i
= 0;done
< device
->NumChan
;i
++)
218 SpeakerAngle
[done
] = device
->SpeakerAngle
[i
]-angle
+ F_PI
*2.0f
;
219 Speaker2Chan
[done
] = device
->Speaker2Chan
[i
];
225 /* NOTE: '< device->NumChan' on the iterators is correct here since
226 * we need to handle index 0. Because the iterators are unsigned,
227 * they'll underflow and wrap to become 0xFFFFFFFF, which will
228 * break as expected. */
229 ALuint done
= device
->NumChan
-1;
230 ALuint i
= device
->NumChan
-1;
231 while(i
< device
->NumChan
&& device
->SpeakerAngle
[i
]-angle
> F_PI
)
233 for(done
= device
->NumChan
-1;i
< device
->NumChan
;done
--)
235 SpeakerAngle
[done
] = device
->SpeakerAngle
[i
]-angle
;
236 Speaker2Chan
[done
] = device
->Speaker2Chan
[i
];
239 for(i
= device
->NumChan
-1;done
< device
->NumChan
;i
--)
241 SpeakerAngle
[done
] = device
->SpeakerAngle
[i
]-angle
- F_PI
*2.0f
;
242 Speaker2Chan
[done
] = device
->Speaker2Chan
[i
];
248 langle
= angle
- hwidth
;
249 rangle
= angle
+ hwidth
;
254 ALuint last
= device
->NumChan
-1;
255 enum Channel chan
= Speaker2Chan
[i
];
257 if(SpeakerAngle
[i
] >= langle
&& SpeakerAngle
[i
] <= rangle
)
259 tmpgains
[chan
] = 1.0f
;
263 if(SpeakerAngle
[i
] < langle
&& SpeakerAngle
[i
+1] > langle
)
265 a
= (langle
-SpeakerAngle
[i
]) /
266 (SpeakerAngle
[i
+1]-SpeakerAngle
[i
]);
267 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, 1.0f
-a
);
269 if(SpeakerAngle
[i
] > rangle
)
271 a
= (F_PI
*2.0f
+ rangle
-SpeakerAngle
[last
]) /
272 (F_PI
*2.0f
+ SpeakerAngle
[i
]-SpeakerAngle
[last
]);
273 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, a
);
275 else if(SpeakerAngle
[last
] < rangle
)
277 a
= (rangle
-SpeakerAngle
[last
]) /
278 (F_PI
*2.0f
+ SpeakerAngle
[i
]-SpeakerAngle
[last
]);
279 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, a
);
283 for(i
= 1;i
< device
->NumChan
-1;i
++)
285 enum Channel chan
= Speaker2Chan
[i
];
286 if(SpeakerAngle
[i
] >= langle
&& SpeakerAngle
[i
] <= rangle
)
288 tmpgains
[chan
] = 1.0f
;
292 if(SpeakerAngle
[i
] < langle
&& SpeakerAngle
[i
+1] > langle
)
294 a
= (langle
-SpeakerAngle
[i
]) /
295 (SpeakerAngle
[i
+1]-SpeakerAngle
[i
]);
296 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, 1.0f
-a
);
298 if(SpeakerAngle
[i
] > rangle
&& SpeakerAngle
[i
-1] < rangle
)
300 a
= (rangle
-SpeakerAngle
[i
-1]) /
301 (SpeakerAngle
[i
]-SpeakerAngle
[i
-1]);
302 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, a
);
307 i
= device
->NumChan
-1;
309 enum Channel chan
= Speaker2Chan
[i
];
310 if(SpeakerAngle
[i
] >= langle
&& SpeakerAngle
[i
] <= rangle
)
312 tmpgains
[Speaker2Chan
[i
]] = 1.0f
;
315 if(SpeakerAngle
[i
] > rangle
&& SpeakerAngle
[i
-1] < rangle
)
317 a
= (rangle
-SpeakerAngle
[i
-1]) /
318 (SpeakerAngle
[i
]-SpeakerAngle
[i
-1]);
319 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, a
);
321 if(SpeakerAngle
[i
] < langle
)
323 a
= (langle
-SpeakerAngle
[i
]) /
324 (F_PI
*2.0f
+ SpeakerAngle
[0]-SpeakerAngle
[i
]);
325 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, 1.0f
-a
);
327 else if(SpeakerAngle
[0] > langle
)
329 a
= (F_PI
*2.0f
+ langle
-SpeakerAngle
[i
]) /
330 (F_PI
*2.0f
+ SpeakerAngle
[0]-SpeakerAngle
[i
]);
331 tmpgains
[chan
] = lerp(tmpgains
[chan
], 1.0f
, 1.0f
-a
);
335 for(i
= 0;i
< device
->NumChan
;i
++)
337 enum Channel chan
= device
->Speaker2Chan
[i
];
338 gains
[chan
] = sqrtf(tmpgains
[chan
]) * ingain
;
343 ALvoid
aluInitPanning(ALCdevice
*Device
)
345 const char *layoutname
= NULL
;
346 enum Channel
*Speaker2Chan
;
347 ALfloat
*SpeakerAngle
;
349 Speaker2Chan
= Device
->Speaker2Chan
;
350 SpeakerAngle
= Device
->SpeakerAngle
;
351 switch(Device
->FmtChans
)
355 Speaker2Chan
[0] = FrontCenter
;
356 SpeakerAngle
[0] = F_PI
/180.0f
* 0.0f
;
362 Speaker2Chan
[0] = FrontLeft
;
363 Speaker2Chan
[1] = FrontRight
;
364 SpeakerAngle
[0] = F_PI
/180.0f
* -90.0f
;
365 SpeakerAngle
[1] = F_PI
/180.0f
* 90.0f
;
366 layoutname
= "layout_stereo";
371 Speaker2Chan
[0] = BackLeft
;
372 Speaker2Chan
[1] = FrontLeft
;
373 Speaker2Chan
[2] = FrontRight
;
374 Speaker2Chan
[3] = BackRight
;
375 SpeakerAngle
[0] = F_PI
/180.0f
* -135.0f
;
376 SpeakerAngle
[1] = F_PI
/180.0f
* -45.0f
;
377 SpeakerAngle
[2] = F_PI
/180.0f
* 45.0f
;
378 SpeakerAngle
[3] = F_PI
/180.0f
* 135.0f
;
379 layoutname
= "layout_quad";
384 Speaker2Chan
[0] = BackLeft
;
385 Speaker2Chan
[1] = FrontLeft
;
386 Speaker2Chan
[2] = FrontCenter
;
387 Speaker2Chan
[3] = FrontRight
;
388 Speaker2Chan
[4] = BackRight
;
389 SpeakerAngle
[0] = F_PI
/180.0f
* -110.0f
;
390 SpeakerAngle
[1] = F_PI
/180.0f
* -30.0f
;
391 SpeakerAngle
[2] = F_PI
/180.0f
* 0.0f
;
392 SpeakerAngle
[3] = F_PI
/180.0f
* 30.0f
;
393 SpeakerAngle
[4] = F_PI
/180.0f
* 110.0f
;
394 layoutname
= "layout_surround51";
399 Speaker2Chan
[0] = SideLeft
;
400 Speaker2Chan
[1] = FrontLeft
;
401 Speaker2Chan
[2] = FrontCenter
;
402 Speaker2Chan
[3] = FrontRight
;
403 Speaker2Chan
[4] = SideRight
;
404 SpeakerAngle
[0] = F_PI
/180.0f
* -90.0f
;
405 SpeakerAngle
[1] = F_PI
/180.0f
* -30.0f
;
406 SpeakerAngle
[2] = F_PI
/180.0f
* 0.0f
;
407 SpeakerAngle
[3] = F_PI
/180.0f
* 30.0f
;
408 SpeakerAngle
[4] = F_PI
/180.0f
* 90.0f
;
409 layoutname
= "layout_side51";
414 Speaker2Chan
[0] = SideLeft
;
415 Speaker2Chan
[1] = FrontLeft
;
416 Speaker2Chan
[2] = FrontCenter
;
417 Speaker2Chan
[3] = FrontRight
;
418 Speaker2Chan
[4] = SideRight
;
419 Speaker2Chan
[5] = BackCenter
;
420 SpeakerAngle
[0] = F_PI
/180.0f
* -90.0f
;
421 SpeakerAngle
[1] = F_PI
/180.0f
* -30.0f
;
422 SpeakerAngle
[2] = F_PI
/180.0f
* 0.0f
;
423 SpeakerAngle
[3] = F_PI
/180.0f
* 30.0f
;
424 SpeakerAngle
[4] = F_PI
/180.0f
* 90.0f
;
425 SpeakerAngle
[5] = F_PI
/180.0f
* 180.0f
;
426 layoutname
= "layout_surround61";
431 Speaker2Chan
[0] = BackLeft
;
432 Speaker2Chan
[1] = SideLeft
;
433 Speaker2Chan
[2] = FrontLeft
;
434 Speaker2Chan
[3] = FrontCenter
;
435 Speaker2Chan
[4] = FrontRight
;
436 Speaker2Chan
[5] = SideRight
;
437 Speaker2Chan
[6] = BackRight
;
438 SpeakerAngle
[0] = F_PI
/180.0f
* -150.0f
;
439 SpeakerAngle
[1] = F_PI
/180.0f
* -90.0f
;
440 SpeakerAngle
[2] = F_PI
/180.0f
* -30.0f
;
441 SpeakerAngle
[3] = F_PI
/180.0f
* 0.0f
;
442 SpeakerAngle
[4] = F_PI
/180.0f
* 30.0f
;
443 SpeakerAngle
[5] = F_PI
/180.0f
* 90.0f
;
444 SpeakerAngle
[6] = F_PI
/180.0f
* 150.0f
;
445 layoutname
= "layout_surround71";
448 if(layoutname
&& Device
->Type
!= Loopback
)
449 SetSpeakerArrangement(layoutname
, SpeakerAngle
, Speaker2Chan
, Device
->NumChan
);