Use an enum for the device type
[openal-soft/openal-hmr.git] / Alc / panning.c
blobfa24be80c0fe27be3ce91b6fa9058c81b22c5695
1 /**
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
21 #include "config.h"
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
29 #include "alMain.h"
30 #include "AL/al.h"
31 #include "AL/alc.h"
32 #include "alu.h"
34 static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MAXCHANNELS],
35 enum Channel Speaker2Chan[MAXCHANNELS], ALint chans)
37 char *confkey, *next;
38 char *layout_str;
39 char *sep, *end;
40 enum Channel val;
41 const char *str;
42 int i;
44 if(!ConfigValueStr(NULL, name, &str) && !ConfigValueStr(NULL, "layout", &str))
45 return;
47 layout_str = strdup(str);
48 next = confkey = layout_str;
49 while(next && *next)
51 confkey = next;
52 next = strchr(confkey, ',');
53 if(next)
55 *next = 0;
56 do {
57 next++;
58 } while(isspace(*next) || *next == ',');
61 sep = strchr(confkey, '=');
62 if(!sep || confkey == sep)
64 ERR("Malformed speaker key: %s\n", confkey);
65 continue;
68 end = sep - 1;
69 while(isspace(*end) && end != confkey)
70 end--;
71 *(++end) = 0;
73 if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
74 val = FRONT_LEFT;
75 else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
76 val = FRONT_RIGHT;
77 else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
78 val = FRONT_CENTER;
79 else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
80 val = BACK_LEFT;
81 else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
82 val = BACK_RIGHT;
83 else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
84 val = BACK_CENTER;
85 else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
86 val = SIDE_LEFT;
87 else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
88 val = SIDE_RIGHT;
89 else
91 ERR("Unknown speaker for %s: \"%s\"\n", name, confkey);
92 continue;
95 *(sep++) = 0;
96 while(isspace(*sep))
97 sep++;
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;
106 else
107 ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
108 break;
112 free(layout_str);
113 layout_str = NULL;
115 for(i = 0;i < chans;i++)
117 int min = i;
118 int i2;
120 for(i2 = i+1;i2 < chans;i2++)
122 if(SpeakerAngle[i2] < SpeakerAngle[min])
123 min = i2;
126 if(min != i)
128 ALfloat tmpf;
129 enum Channel tmpc;
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)
155 ALint pos = 0;
156 ALfloat denom = aluFabs(re) + aluFabs(im);
157 if(denom > 0.0f)
158 pos = (ALint)(QUADRANT_NUM*aluFabs(im) / denom + 0.5);
160 if(re < 0.0f)
161 pos = 2 * QUADRANT_NUM - pos;
162 if(im < 0.0f)
163 pos = LUT_NUM - pos;
164 return pos%LUT_NUM;
167 ALvoid aluInitPanning(ALCdevice *Device)
169 ALfloat SpeakerAngle[MAXCHANNELS];
170 const char *layoutname = NULL;
171 enum Channel *Speaker2Chan;
172 ALfloat Alpha, Theta;
173 ALint pos;
174 ALuint s;
176 Speaker2Chan = Device->Speaker2Chan;
177 switch(Device->FmtChans)
179 case DevFmtMono:
180 Device->NumChan = 1;
181 Speaker2Chan[0] = FRONT_CENTER;
182 SpeakerAngle[0] = F_PI/180.0f * 0.0f;
183 layoutname = NULL;
184 break;
186 case DevFmtStereo:
187 Device->NumChan = 2;
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";
193 break;
195 case DevFmtQuad:
196 Device->NumChan = 4;
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";
206 break;
208 case DevFmtX51:
209 Device->NumChan = 5;
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";
221 break;
223 case DevFmtX51Side:
224 Device->NumChan = 5;
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";
236 break;
238 case DevFmtX61:
239 Device->NumChan = 6;
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";
253 break;
255 case DevFmtX71:
256 Device->NumChan = 7;
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";
272 break;
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;
288 continue;
291 /* source angle */
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);
304 break;
307 if(s == Device->NumChan - 1)
309 /* source between last and first speaker */
310 if(Theta < SpeakerAngle[0])
311 Theta += F_PI*2.0f;
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);