Store double formats as float
[openal-soft.git] / Alc / panning.c
blob43c55cad3b2c04b97a00df6f35fac26b2c132a21
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[OUTPUTCHANNELS],
35 Channel Speaker2Chan[OUTPUTCHANNELS], ALint chans)
37 char layout_str[256];
38 char *confkey, *next;
39 char *sep, *end;
40 Channel val;
41 int i;
43 strncpy(layout_str, GetConfigValue(NULL, name, ""), sizeof(layout_str));
44 layout_str[sizeof(layout_str)-1] = 0;
46 if(!layout_str[0])
47 return;
49 next = confkey = layout_str;
50 while(next && *next)
52 confkey = next;
53 next = strchr(confkey, ',');
54 if(next)
56 *next = 0;
57 do {
58 next++;
59 } while(isspace(*next) || *next == ',');
62 sep = strchr(confkey, '=');
63 if(!sep || confkey == sep)
64 continue;
66 end = sep - 1;
67 while(isspace(*end) && end != confkey)
68 end--;
69 *(++end) = 0;
71 if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
72 val = FRONT_LEFT;
73 else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
74 val = FRONT_RIGHT;
75 else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
76 val = FRONT_CENTER;
77 else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
78 val = BACK_LEFT;
79 else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
80 val = BACK_RIGHT;
81 else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
82 val = BACK_CENTER;
83 else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
84 val = SIDE_LEFT;
85 else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
86 val = SIDE_RIGHT;
87 else
89 AL_PRINT("Unknown speaker for %s: \"%s\"\n", name, confkey);
90 continue;
93 *(sep++) = 0;
94 while(isspace(*sep))
95 sep++;
97 for(i = 0;i < chans;i++)
99 if(Speaker2Chan[i] == val)
101 long angle = strtol(sep, NULL, 10);
102 if(angle >= -180 && angle <= 180)
103 SpeakerAngle[i] = angle * M_PI/180.0f;
104 else
105 AL_PRINT("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
106 break;
111 for(i = 0;i < chans;i++)
113 int min = i;
114 int i2;
116 for(i2 = i+1;i2 < chans;i2++)
118 if(SpeakerAngle[i2] < SpeakerAngle[min])
119 min = i2;
122 if(min != i)
124 ALfloat tmpf;
125 Channel tmpc;
127 tmpf = SpeakerAngle[i];
128 SpeakerAngle[i] = SpeakerAngle[min];
129 SpeakerAngle[min] = tmpf;
131 tmpc = Speaker2Chan[i];
132 Speaker2Chan[i] = Speaker2Chan[min];
133 Speaker2Chan[min] = tmpc;
138 static ALfloat aluLUTpos2Angle(ALint pos)
140 if(pos < QUADRANT_NUM)
141 return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos));
142 if(pos < 2 * QUADRANT_NUM)
143 return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos));
144 if(pos < 3 * QUADRANT_NUM)
145 return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - M_PI;
146 return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - M_PI_2;
149 ALint aluCart2LUTpos(ALfloat re, ALfloat im)
151 ALint pos = 0;
152 ALfloat denom = aluFabs(re) + aluFabs(im);
153 if(denom > 0.0f)
154 pos = (ALint)(QUADRANT_NUM*aluFabs(im) / denom + 0.5);
156 if(re < 0.0)
157 pos = 2 * QUADRANT_NUM - pos;
158 if(im < 0.0)
159 pos = LUT_NUM - pos;
160 return pos%LUT_NUM;
163 ALvoid aluInitPanning(ALCdevice *Device)
165 ALfloat SpeakerAngle[OUTPUTCHANNELS];
166 ALfloat (*Matrix)[OUTPUTCHANNELS];
167 Channel *Speaker2Chan;
168 ALfloat Alpha, Theta;
169 ALfloat *PanningLUT;
170 ALint pos, offset;
171 ALuint s, s2;
173 for(s = 0;s < OUTPUTCHANNELS;s++)
175 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
176 Device->ChannelMatrix[s][s2] = ((s==s2) ? 1.0f : 0.0f);
179 Speaker2Chan = Device->Speaker2Chan;
180 Matrix = Device->ChannelMatrix;
181 switch(Device->Format)
183 case AL_FORMAT_MONO8:
184 case AL_FORMAT_MONO16:
185 case AL_FORMAT_MONO_FLOAT32:
186 Matrix[FRONT_LEFT][FRONT_CENTER] = aluSqrt(0.5);
187 Matrix[FRONT_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
188 Matrix[SIDE_LEFT][FRONT_CENTER] = aluSqrt(0.5);
189 Matrix[SIDE_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
190 Matrix[BACK_LEFT][FRONT_CENTER] = aluSqrt(0.5);
191 Matrix[BACK_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
192 Matrix[BACK_CENTER][FRONT_CENTER] = 1.0f;
193 Device->NumChan = 1;
194 Speaker2Chan[0] = FRONT_CENTER;
195 SpeakerAngle[0] = 0.0f * M_PI/180.0f;
196 break;
198 case AL_FORMAT_STEREO8:
199 case AL_FORMAT_STEREO16:
200 case AL_FORMAT_STEREO_FLOAT32:
201 Matrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
202 Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
203 Matrix[SIDE_LEFT][FRONT_LEFT] = 1.0f;
204 Matrix[SIDE_RIGHT][FRONT_RIGHT] = 1.0f;
205 Matrix[BACK_LEFT][FRONT_LEFT] = 1.0f;
206 Matrix[BACK_RIGHT][FRONT_RIGHT] = 1.0f;
207 Matrix[BACK_CENTER][FRONT_LEFT] = aluSqrt(0.5);
208 Matrix[BACK_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
209 Device->NumChan = 2;
210 Speaker2Chan[0] = FRONT_LEFT;
211 Speaker2Chan[1] = FRONT_RIGHT;
212 SpeakerAngle[0] = -90.0f * M_PI/180.0f;
213 SpeakerAngle[1] = 90.0f * M_PI/180.0f;
214 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
215 break;
217 case AL_FORMAT_QUAD8:
218 case AL_FORMAT_QUAD16:
219 case AL_FORMAT_QUAD32:
220 Matrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
221 Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
222 Matrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
223 Matrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
224 Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
225 Matrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
226 Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
227 Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
228 Device->NumChan = 4;
229 Speaker2Chan[0] = BACK_LEFT;
230 Speaker2Chan[1] = FRONT_LEFT;
231 Speaker2Chan[2] = FRONT_RIGHT;
232 Speaker2Chan[3] = BACK_RIGHT;
233 SpeakerAngle[0] = -135.0f * M_PI/180.0f;
234 SpeakerAngle[1] = -45.0f * M_PI/180.0f;
235 SpeakerAngle[2] = 45.0f * M_PI/180.0f;
236 SpeakerAngle[3] = 135.0f * M_PI/180.0f;
237 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
238 break;
240 case AL_FORMAT_51CHN8:
241 case AL_FORMAT_51CHN16:
242 case AL_FORMAT_51CHN32:
243 Matrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
244 Matrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
245 Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
246 Matrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
247 Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
248 Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
249 Device->NumChan = 5;
250 Speaker2Chan[0] = BACK_LEFT;
251 Speaker2Chan[1] = FRONT_LEFT;
252 Speaker2Chan[2] = FRONT_CENTER;
253 Speaker2Chan[3] = FRONT_RIGHT;
254 Speaker2Chan[4] = BACK_RIGHT;
255 SpeakerAngle[0] = -110.0f * M_PI/180.0f;
256 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
257 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
258 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
259 SpeakerAngle[4] = 110.0f * M_PI/180.0f;
260 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
261 break;
263 case AL_FORMAT_61CHN8:
264 case AL_FORMAT_61CHN16:
265 case AL_FORMAT_61CHN32:
266 Matrix[BACK_LEFT][BACK_CENTER] = aluSqrt(0.5);
267 Matrix[BACK_LEFT][SIDE_LEFT] = aluSqrt(0.5);
268 Matrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(0.5);
269 Matrix[BACK_RIGHT][SIDE_RIGHT] = aluSqrt(0.5);
270 Device->NumChan = 6;
271 Speaker2Chan[0] = SIDE_LEFT;
272 Speaker2Chan[1] = FRONT_LEFT;
273 Speaker2Chan[2] = FRONT_CENTER;
274 Speaker2Chan[3] = FRONT_RIGHT;
275 Speaker2Chan[4] = SIDE_RIGHT;
276 Speaker2Chan[5] = BACK_CENTER;
277 SpeakerAngle[0] = -90.0f * M_PI/180.0f;
278 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
279 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
280 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
281 SpeakerAngle[4] = 90.0f * M_PI/180.0f;
282 SpeakerAngle[5] = 180.0f * M_PI/180.0f;
283 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
284 break;
286 case AL_FORMAT_71CHN8:
287 case AL_FORMAT_71CHN16:
288 case AL_FORMAT_71CHN32:
289 Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
290 Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
291 Device->NumChan = 7;
292 Speaker2Chan[0] = BACK_LEFT;
293 Speaker2Chan[1] = SIDE_LEFT;
294 Speaker2Chan[2] = FRONT_LEFT;
295 Speaker2Chan[3] = FRONT_CENTER;
296 Speaker2Chan[4] = FRONT_RIGHT;
297 Speaker2Chan[5] = SIDE_RIGHT;
298 Speaker2Chan[6] = BACK_RIGHT;
299 SpeakerAngle[0] = -150.0f * M_PI/180.0f;
300 SpeakerAngle[1] = -90.0f * M_PI/180.0f;
301 SpeakerAngle[2] = -30.0f * M_PI/180.0f;
302 SpeakerAngle[3] = 0.0f * M_PI/180.0f;
303 SpeakerAngle[4] = 30.0f * M_PI/180.0f;
304 SpeakerAngle[5] = 90.0f * M_PI/180.0f;
305 SpeakerAngle[6] = 150.0f * M_PI/180.0f;
306 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
307 break;
309 default:
310 assert(0);
313 if(GetConfigValueBool(NULL, "scalemix", 0))
315 ALfloat maxout = 1.0f;
316 for(s = 0;s < OUTPUTCHANNELS;s++)
318 ALfloat out = 0.0f;
319 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
320 out += Device->ChannelMatrix[s2][s];
321 maxout = __max(maxout, out);
324 maxout = 1.0f/maxout;
325 for(s = 0;s < OUTPUTCHANNELS;s++)
327 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
328 Device->ChannelMatrix[s2][s] *= maxout;
332 PanningLUT = Device->PanningLUT;
333 for(pos = 0; pos < LUT_NUM; pos++)
335 /* clear all values */
336 offset = OUTPUTCHANNELS * pos;
337 for(s = 0; s < OUTPUTCHANNELS; s++)
338 PanningLUT[offset+s] = 0.0f;
340 if(Device->NumChan == 1)
342 PanningLUT[offset + Speaker2Chan[0]] = 1.0f;
343 continue;
346 /* source angle */
347 Theta = aluLUTpos2Angle(pos);
349 /* set panning values */
350 for(s = 0; s < Device->NumChan - 1; s++)
352 if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1])
354 /* source between speaker s and speaker s+1 */
355 Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
356 (SpeakerAngle[s+1]-SpeakerAngle[s]);
357 PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
358 PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha);
359 break;
362 if(s == Device->NumChan - 1)
364 /* source between last and first speaker */
365 if(Theta < SpeakerAngle[0])
366 Theta += 2.0f * M_PI;
367 Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
368 (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]);
369 PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
370 PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha);