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
;
142 static ALfloat
aluLUTpos2Angle(ALint pos
)
144 if(pos
< QUADRANT_NUM
)
145 return aluAtan((ALfloat
)pos
/ (ALfloat
)(QUADRANT_NUM
- pos
));
146 if(pos
< 2 * QUADRANT_NUM
)
147 return F_PI_2
+ aluAtan((ALfloat
)(pos
- QUADRANT_NUM
) / (ALfloat
)(2 * QUADRANT_NUM
- pos
));
148 if(pos
< 3 * QUADRANT_NUM
)
149 return aluAtan((ALfloat
)(pos
- 2 * QUADRANT_NUM
) / (ALfloat
)(3 * QUADRANT_NUM
- pos
)) - F_PI
;
150 return aluAtan((ALfloat
)(pos
- 3 * QUADRANT_NUM
) / (ALfloat
)(4 * QUADRANT_NUM
- pos
)) - F_PI_2
;
153 ALint
aluCart2LUTpos(ALfloat re
, ALfloat im
)
156 ALfloat denom
= aluFabs(re
) + aluFabs(im
);
158 pos
= (ALint
)(QUADRANT_NUM
*aluFabs(im
) / denom
+ 0.5);
161 pos
= 2 * QUADRANT_NUM
- pos
;
167 ALvoid
aluInitPanning(ALCdevice
*Device
)
169 ALfloat SpeakerAngle
[MAXCHANNELS
];
170 const char *layoutname
= NULL
;
171 enum Channel
*Speaker2Chan
;
172 ALfloat Alpha
, Theta
;
176 Speaker2Chan
= Device
->Speaker2Chan
;
177 switch(Device
->FmtChans
)
181 Speaker2Chan
[0] = FRONT_CENTER
;
182 SpeakerAngle
[0] = F_PI
/180.0f
* 0.0f
;
188 Speaker2Chan
[0] = FRONT_LEFT
;
189 Speaker2Chan
[1] = FRONT_RIGHT
;
190 SpeakerAngle
[0] = F_PI
/180.0f
* -30.0f
;
191 SpeakerAngle
[1] = F_PI
/180.0f
* 30.0f
;
192 layoutname
= "layout_STEREO";
197 Speaker2Chan
[0] = BACK_LEFT
;
198 Speaker2Chan
[1] = FRONT_LEFT
;
199 Speaker2Chan
[2] = FRONT_RIGHT
;
200 Speaker2Chan
[3] = BACK_RIGHT
;
201 SpeakerAngle
[0] = F_PI
/180.0f
* -135.0f
;
202 SpeakerAngle
[1] = F_PI
/180.0f
* -45.0f
;
203 SpeakerAngle
[2] = F_PI
/180.0f
* 45.0f
;
204 SpeakerAngle
[3] = F_PI
/180.0f
* 135.0f
;
205 layoutname
= "layout_QUAD";
210 Speaker2Chan
[0] = BACK_LEFT
;
211 Speaker2Chan
[1] = FRONT_LEFT
;
212 Speaker2Chan
[2] = FRONT_CENTER
;
213 Speaker2Chan
[3] = FRONT_RIGHT
;
214 Speaker2Chan
[4] = BACK_RIGHT
;
215 SpeakerAngle
[0] = F_PI
/180.0f
* -110.0f
;
216 SpeakerAngle
[1] = F_PI
/180.0f
* -30.0f
;
217 SpeakerAngle
[2] = F_PI
/180.0f
* 0.0f
;
218 SpeakerAngle
[3] = F_PI
/180.0f
* 30.0f
;
219 SpeakerAngle
[4] = F_PI
/180.0f
* 110.0f
;
220 layoutname
= "layout_51CHN";
225 Speaker2Chan
[0] = SIDE_LEFT
;
226 Speaker2Chan
[1] = FRONT_LEFT
;
227 Speaker2Chan
[2] = FRONT_CENTER
;
228 Speaker2Chan
[3] = FRONT_RIGHT
;
229 Speaker2Chan
[4] = SIDE_RIGHT
;
230 SpeakerAngle
[0] = F_PI
/180.0f
* -90.0f
;
231 SpeakerAngle
[1] = F_PI
/180.0f
* -30.0f
;
232 SpeakerAngle
[2] = F_PI
/180.0f
* 0.0f
;
233 SpeakerAngle
[3] = F_PI
/180.0f
* 30.0f
;
234 SpeakerAngle
[4] = F_PI
/180.0f
* 90.0f
;
235 layoutname
= "layout_51SIDECHN";
240 Speaker2Chan
[0] = SIDE_LEFT
;
241 Speaker2Chan
[1] = FRONT_LEFT
;
242 Speaker2Chan
[2] = FRONT_CENTER
;
243 Speaker2Chan
[3] = FRONT_RIGHT
;
244 Speaker2Chan
[4] = SIDE_RIGHT
;
245 Speaker2Chan
[5] = BACK_CENTER
;
246 SpeakerAngle
[0] = F_PI
/180.0f
* -90.0f
;
247 SpeakerAngle
[1] = F_PI
/180.0f
* -30.0f
;
248 SpeakerAngle
[2] = F_PI
/180.0f
* 0.0f
;
249 SpeakerAngle
[3] = F_PI
/180.0f
* 30.0f
;
250 SpeakerAngle
[4] = F_PI
/180.0f
* 90.0f
;
251 SpeakerAngle
[5] = F_PI
/180.0f
* 180.0f
;
252 layoutname
= "layout_61CHN";
257 Speaker2Chan
[0] = BACK_LEFT
;
258 Speaker2Chan
[1] = SIDE_LEFT
;
259 Speaker2Chan
[2] = FRONT_LEFT
;
260 Speaker2Chan
[3] = FRONT_CENTER
;
261 Speaker2Chan
[4] = FRONT_RIGHT
;
262 Speaker2Chan
[5] = SIDE_RIGHT
;
263 Speaker2Chan
[6] = BACK_RIGHT
;
264 SpeakerAngle
[0] = F_PI
/180.0f
* -150.0f
;
265 SpeakerAngle
[1] = F_PI
/180.0f
* -90.0f
;
266 SpeakerAngle
[2] = F_PI
/180.0f
* -30.0f
;
267 SpeakerAngle
[3] = F_PI
/180.0f
* 0.0f
;
268 SpeakerAngle
[4] = F_PI
/180.0f
* 30.0f
;
269 SpeakerAngle
[5] = F_PI
/180.0f
* 90.0f
;
270 SpeakerAngle
[6] = F_PI
/180.0f
* 150.0f
;
271 layoutname
= "layout_71CHN";
274 if(layoutname
&& Device
->Type
!= Loopback
)
275 SetSpeakerArrangement(layoutname
, SpeakerAngle
, Speaker2Chan
, Device
->NumChan
);
277 for(pos
= 0; pos
< LUT_NUM
; pos
++)
279 ALfloat
*PanningLUT
= Device
->PanningLUT
[pos
];
281 /* clear all values */
282 for(s
= 0; s
< MAXCHANNELS
; s
++)
283 PanningLUT
[s
] = 0.0f
;
285 if(Device
->NumChan
== 1)
287 PanningLUT
[Speaker2Chan
[0]] = 1.0f
;
292 Theta
= aluLUTpos2Angle(pos
);
294 /* set panning values */
295 for(s
= 0; s
< Device
->NumChan
- 1; s
++)
297 if(Theta
>= SpeakerAngle
[s
] && Theta
< SpeakerAngle
[s
+1])
299 /* source between speaker s and speaker s+1 */
300 Alpha
= (Theta
-SpeakerAngle
[s
]) /
301 (SpeakerAngle
[s
+1]-SpeakerAngle
[s
]);
302 PanningLUT
[Speaker2Chan
[s
]] = aluSqrt(1.0f
-Alpha
);
303 PanningLUT
[Speaker2Chan
[s
+1]] = aluSqrt( Alpha
);
307 if(s
== Device
->NumChan
- 1)
309 /* source between last and first speaker */
310 if(Theta
< SpeakerAngle
[0])
312 Alpha
= (Theta
-SpeakerAngle
[s
]) /
313 (F_PI
*2.0f
+ SpeakerAngle
[0]-SpeakerAngle
[s
]);
314 PanningLUT
[Speaker2Chan
[s
]] = aluSqrt(1.0f
-Alpha
);
315 PanningLUT
[Speaker2Chan
[0]] = aluSqrt( Alpha
);