Allow accessing the buffer data as multiple data types in the mixer
[openal-soft.git] / Alc / panning.c
blob5c0f68fd3e9ddea2138337fe7badf59354b9e79e
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 ALvoid aluInitPanning(ALCdevice *Device)
151 ALfloat SpeakerAngle[OUTPUTCHANNELS];
152 ALfloat (*Matrix)[OUTPUTCHANNELS];
153 Channel *Speaker2Chan;
154 ALfloat Alpha, Theta;
155 ALfloat *PanningLUT;
156 ALint pos, offset;
157 ALuint s, s2;
159 for(s = 0;s < OUTPUTCHANNELS;s++)
161 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
162 Device->ChannelMatrix[s][s2] = ((s==s2) ? 1.0f : 0.0f);
165 Speaker2Chan = Device->Speaker2Chan;
166 Matrix = Device->ChannelMatrix;
167 switch(Device->Format)
169 case AL_FORMAT_MONO8:
170 case AL_FORMAT_MONO16:
171 case AL_FORMAT_MONO_FLOAT32:
172 Matrix[FRONT_LEFT][FRONT_CENTER] = aluSqrt(0.5);
173 Matrix[FRONT_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
174 Matrix[SIDE_LEFT][FRONT_CENTER] = aluSqrt(0.5);
175 Matrix[SIDE_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
176 Matrix[BACK_LEFT][FRONT_CENTER] = aluSqrt(0.5);
177 Matrix[BACK_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
178 Matrix[BACK_CENTER][FRONT_CENTER] = 1.0f;
179 Device->NumChan = 1;
180 Speaker2Chan[0] = FRONT_CENTER;
181 SpeakerAngle[0] = 0.0f * M_PI/180.0f;
182 break;
184 case AL_FORMAT_STEREO8:
185 case AL_FORMAT_STEREO16:
186 case AL_FORMAT_STEREO_FLOAT32:
187 Matrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
188 Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
189 Matrix[SIDE_LEFT][FRONT_LEFT] = 1.0f;
190 Matrix[SIDE_RIGHT][FRONT_RIGHT] = 1.0f;
191 Matrix[BACK_LEFT][FRONT_LEFT] = 1.0f;
192 Matrix[BACK_RIGHT][FRONT_RIGHT] = 1.0f;
193 Matrix[BACK_CENTER][FRONT_LEFT] = aluSqrt(0.5);
194 Matrix[BACK_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
195 Device->NumChan = 2;
196 Speaker2Chan[0] = FRONT_LEFT;
197 Speaker2Chan[1] = FRONT_RIGHT;
198 SpeakerAngle[0] = -90.0f * M_PI/180.0f;
199 SpeakerAngle[1] = 90.0f * M_PI/180.0f;
200 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
201 break;
203 case AL_FORMAT_QUAD8:
204 case AL_FORMAT_QUAD16:
205 case AL_FORMAT_QUAD32:
206 Matrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
207 Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
208 Matrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
209 Matrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
210 Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
211 Matrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
212 Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
213 Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
214 Device->NumChan = 4;
215 Speaker2Chan[0] = BACK_LEFT;
216 Speaker2Chan[1] = FRONT_LEFT;
217 Speaker2Chan[2] = FRONT_RIGHT;
218 Speaker2Chan[3] = BACK_RIGHT;
219 SpeakerAngle[0] = -135.0f * M_PI/180.0f;
220 SpeakerAngle[1] = -45.0f * M_PI/180.0f;
221 SpeakerAngle[2] = 45.0f * M_PI/180.0f;
222 SpeakerAngle[3] = 135.0f * M_PI/180.0f;
223 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
224 break;
226 case AL_FORMAT_51CHN8:
227 case AL_FORMAT_51CHN16:
228 case AL_FORMAT_51CHN32:
229 Matrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
230 Matrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
231 Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
232 Matrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
233 Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
234 Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
235 Device->NumChan = 5;
236 Speaker2Chan[0] = BACK_LEFT;
237 Speaker2Chan[1] = FRONT_LEFT;
238 Speaker2Chan[2] = FRONT_CENTER;
239 Speaker2Chan[3] = FRONT_RIGHT;
240 Speaker2Chan[4] = BACK_RIGHT;
241 SpeakerAngle[0] = -110.0f * M_PI/180.0f;
242 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
243 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
244 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
245 SpeakerAngle[4] = 110.0f * M_PI/180.0f;
246 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
247 break;
249 case AL_FORMAT_61CHN8:
250 case AL_FORMAT_61CHN16:
251 case AL_FORMAT_61CHN32:
252 Matrix[BACK_LEFT][BACK_CENTER] = aluSqrt(0.5);
253 Matrix[BACK_LEFT][SIDE_LEFT] = aluSqrt(0.5);
254 Matrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(0.5);
255 Matrix[BACK_RIGHT][SIDE_RIGHT] = aluSqrt(0.5);
256 Device->NumChan = 6;
257 Speaker2Chan[0] = SIDE_LEFT;
258 Speaker2Chan[1] = FRONT_LEFT;
259 Speaker2Chan[2] = FRONT_CENTER;
260 Speaker2Chan[3] = FRONT_RIGHT;
261 Speaker2Chan[4] = SIDE_RIGHT;
262 Speaker2Chan[5] = BACK_CENTER;
263 SpeakerAngle[0] = -90.0f * M_PI/180.0f;
264 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
265 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
266 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
267 SpeakerAngle[4] = 90.0f * M_PI/180.0f;
268 SpeakerAngle[5] = 180.0f * M_PI/180.0f;
269 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
270 break;
272 case AL_FORMAT_71CHN8:
273 case AL_FORMAT_71CHN16:
274 case AL_FORMAT_71CHN32:
275 Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
276 Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
277 Device->NumChan = 7;
278 Speaker2Chan[0] = BACK_LEFT;
279 Speaker2Chan[1] = SIDE_LEFT;
280 Speaker2Chan[2] = FRONT_LEFT;
281 Speaker2Chan[3] = FRONT_CENTER;
282 Speaker2Chan[4] = FRONT_RIGHT;
283 Speaker2Chan[5] = SIDE_RIGHT;
284 Speaker2Chan[6] = BACK_RIGHT;
285 SpeakerAngle[0] = -150.0f * M_PI/180.0f;
286 SpeakerAngle[1] = -90.0f * M_PI/180.0f;
287 SpeakerAngle[2] = -30.0f * M_PI/180.0f;
288 SpeakerAngle[3] = 0.0f * M_PI/180.0f;
289 SpeakerAngle[4] = 30.0f * M_PI/180.0f;
290 SpeakerAngle[5] = 90.0f * M_PI/180.0f;
291 SpeakerAngle[6] = 150.0f * M_PI/180.0f;
292 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
293 break;
295 default:
296 assert(0);
299 if(GetConfigValueBool(NULL, "scalemix", 0))
301 ALfloat maxout = 1.0f;
302 for(s = 0;s < OUTPUTCHANNELS;s++)
304 ALfloat out = 0.0f;
305 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
306 out += Device->ChannelMatrix[s2][s];
307 maxout = __max(maxout, out);
310 maxout = 1.0f/maxout;
311 for(s = 0;s < OUTPUTCHANNELS;s++)
313 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
314 Device->ChannelMatrix[s2][s] *= maxout;
318 PanningLUT = Device->PanningLUT;
319 for(pos = 0; pos < LUT_NUM; pos++)
321 /* clear all values */
322 offset = OUTPUTCHANNELS * pos;
323 for(s = 0; s < OUTPUTCHANNELS; s++)
324 PanningLUT[offset+s] = 0.0f;
326 if(Device->NumChan == 1)
328 PanningLUT[offset + Speaker2Chan[0]] = 1.0f;
329 continue;
332 /* source angle */
333 Theta = aluLUTpos2Angle(pos);
335 /* set panning values */
336 for(s = 0; s < Device->NumChan - 1; s++)
338 if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1])
340 /* source between speaker s and speaker s+1 */
341 Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
342 (SpeakerAngle[s+1]-SpeakerAngle[s]);
343 PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
344 PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha);
345 break;
348 if(s == Device->NumChan - 1)
350 /* source between last and first speaker */
351 if(Theta < SpeakerAngle[0])
352 Theta += 2.0f * M_PI;
353 Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
354 (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]);
355 PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
356 PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha);