zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
panning.c
Go to the documentation of this file.
1 
21 #include "config.h"
22 
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
28 
29 #include "alMain.h"
30 #include "AL/al.h"
31 #include "AL/alc.h"
32 #include "alu.h"
33 
34 static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MaxChannels],
35  enum Channel Speaker2Chan[MaxChannels], ALint chans)
36 {
37  char *confkey, *next;
38  char *layout_str;
39  char *sep, *end;
40  enum Channel val;
41  const char *str;
42  int i;
43 
44  if(!ConfigValueStr(NULL, name, &str) && !ConfigValueStr(NULL, "layout", &str))
45  return;
46 
47  layout_str = strdup(str);
48  next = confkey = layout_str;
49  while(next && *next)
50  {
51  confkey = next;
52  next = strchr(confkey, ',');
53  if(next)
54  {
55  *next = 0;
56  do {
57  next++;
58  } while(isspace(*next) || *next == ',');
59  }
60 
61  sep = strchr(confkey, '=');
62  if(!sep || confkey == sep)
63  {
64  ERR("Malformed speaker key: %s\n", confkey);
65  continue;
66  }
67 
68  end = sep - 1;
69  while(isspace(*end) && end != confkey)
70  end--;
71  *(++end) = 0;
72 
73  if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
74  val = FrontLeft;
75  else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
76  val = FrontRight;
77  else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
78  val = FrontCenter;
79  else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
80  val = BackLeft;
81  else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
82  val = BackRight;
83  else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
84  val = BackCenter;
85  else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
86  val = SideLeft;
87  else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
88  val = SideRight;
89  else
90  {
91  ERR("Unknown speaker for %s: \"%s\"\n", name, confkey);
92  continue;
93  }
94 
95  *(sep++) = 0;
96  while(isspace(*sep))
97  sep++;
98 
99  for(i = 0;i < chans;i++)
100  {
101  if(Speaker2Chan[i] == val)
102  {
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;
109  }
110  }
111  }
112  free(layout_str);
113  layout_str = NULL;
114 
115  for(i = 0;i < chans;i++)
116  {
117  int min = i;
118  int i2;
119 
120  for(i2 = i+1;i2 < chans;i2++)
121  {
122  if(SpeakerAngle[i2] < SpeakerAngle[min])
123  min = i2;
124  }
125 
126  if(min != i)
127  {
128  ALfloat tmpf;
129  enum Channel tmpc;
130 
131  tmpf = SpeakerAngle[i];
132  SpeakerAngle[i] = SpeakerAngle[min];
133  SpeakerAngle[min] = tmpf;
134 
135  tmpc = Speaker2Chan[i];
136  Speaker2Chan[i] = Speaker2Chan[min];
137  Speaker2Chan[min] = tmpc;
138  }
139  }
140 }
141 
142 
149 ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat *gains)
150 {
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;
155  ALfloat a;
156  ALuint i;
157 
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];
162 
163  /* Some easy special-cases first... */
164  if(device->NumChan == 1 || hwidth >= F_PI)
165  {
166  /* Full coverage for all speakers. */
167  for(i = 0;i < device->NumChan;i++)
168  {
169  enum Channel chan = Speaker2Chan[i];
170  gains[chan] = ingain;
171  }
172  return;
173  }
174  if(hwidth <= 0.0f)
175  {
176  /* Infinitely small sound point. */
177  for(i = 0;i < device->NumChan-1;i++)
178  {
179  if(angle >= SpeakerAngle[i] && angle < SpeakerAngle[i+1])
180  {
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;
186  return;
187  }
188  }
189  /* Sound is between last and first speakers */
190  if(angle < SpeakerAngle[0])
191  angle += F_PI*2.0f;
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;
196  return;
197  }
198 
199  if(fabsf(angle)+hwidth > F_PI)
200  {
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. */
204  if(angle > 0.0f)
205  {
206  ALuint done = 0;
207  ALuint i = 0;
208  while(i < device->NumChan && device->SpeakerAngle[i]-angle < -F_PI)
209  i++;
210  for(done = 0;i < device->NumChan;done++)
211  {
212  SpeakerAngle[done] = device->SpeakerAngle[i]-angle;
213  Speaker2Chan[done] = device->Speaker2Chan[i];
214  i++;
215  }
216  for(i = 0;done < device->NumChan;i++)
217  {
218  SpeakerAngle[done] = device->SpeakerAngle[i]-angle + F_PI*2.0f;
219  Speaker2Chan[done] = device->Speaker2Chan[i];
220  done++;
221  }
222  }
223  else
224  {
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)
232  i--;
233  for(done = device->NumChan-1;i < device->NumChan;done--)
234  {
235  SpeakerAngle[done] = device->SpeakerAngle[i]-angle;
236  Speaker2Chan[done] = device->Speaker2Chan[i];
237  i--;
238  }
239  for(i = device->NumChan-1;done < device->NumChan;i--)
240  {
241  SpeakerAngle[done] = device->SpeakerAngle[i]-angle - F_PI*2.0f;
242  Speaker2Chan[done] = device->Speaker2Chan[i];
243  done--;
244  }
245  }
246  angle = 0.0f;
247  }
248  langle = angle - hwidth;
249  rangle = angle + hwidth;
250 
251  /* First speaker */
252  i = 0;
253  do {
254  ALuint last = device->NumChan-1;
255  enum Channel chan = Speaker2Chan[i];
256 
257  if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
258  {
259  tmpgains[chan] = 1.0f;
260  continue;
261  }
262 
263  if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
264  {
265  a = (langle-SpeakerAngle[i]) /
266  (SpeakerAngle[i+1]-SpeakerAngle[i]);
267  tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
268  }
269  if(SpeakerAngle[i] > rangle)
270  {
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);
274  }
275  else if(SpeakerAngle[last] < rangle)
276  {
277  a = (rangle-SpeakerAngle[last]) /
278  (F_PI*2.0f + SpeakerAngle[i]-SpeakerAngle[last]);
279  tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
280  }
281  } while(0);
282 
283  for(i = 1;i < device->NumChan-1;i++)
284  {
285  enum Channel chan = Speaker2Chan[i];
286  if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
287  {
288  tmpgains[chan] = 1.0f;
289  continue;
290  }
291 
292  if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
293  {
294  a = (langle-SpeakerAngle[i]) /
295  (SpeakerAngle[i+1]-SpeakerAngle[i]);
296  tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
297  }
298  if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
299  {
300  a = (rangle-SpeakerAngle[i-1]) /
301  (SpeakerAngle[i]-SpeakerAngle[i-1]);
302  tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
303  }
304  }
305 
306  /* Last speaker */
307  i = device->NumChan-1;
308  do {
309  enum Channel chan = Speaker2Chan[i];
310  if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
311  {
312  tmpgains[Speaker2Chan[i]] = 1.0f;
313  continue;
314  }
315  if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
316  {
317  a = (rangle-SpeakerAngle[i-1]) /
318  (SpeakerAngle[i]-SpeakerAngle[i-1]);
319  tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
320  }
321  if(SpeakerAngle[i] < langle)
322  {
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);
326  }
327  else if(SpeakerAngle[0] > langle)
328  {
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);
332  }
333  } while(0);
334 
335  for(i = 0;i < device->NumChan;i++)
336  {
337  enum Channel chan = device->Speaker2Chan[i];
338  gains[chan] = sqrtf(tmpgains[chan]) * ingain;
339  }
340 }
341 
342 
344 {
345  const char *layoutname = NULL;
346  enum Channel *Speaker2Chan;
347  ALfloat *SpeakerAngle;
348 
349  Speaker2Chan = Device->Speaker2Chan;
350  SpeakerAngle = Device->SpeakerAngle;
351  switch(Device->FmtChans)
352  {
353  case DevFmtMono:
354  Device->NumChan = 1;
355  Speaker2Chan[0] = FrontCenter;
356  SpeakerAngle[0] = F_PI/180.0f * 0.0f;
357  layoutname = NULL;
358  break;
359 
360  case DevFmtStereo:
361  Device->NumChan = 2;
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";
367  break;
368 
369  case DevFmtQuad:
370  Device->NumChan = 4;
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";
380  break;
381 
382  case DevFmtX51:
383  Device->NumChan = 5;
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";
395  break;
396 
397  case DevFmtX51Side:
398  Device->NumChan = 5;
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";
410  break;
411 
412  case DevFmtX61:
413  Device->NumChan = 6;
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";
427  break;
428 
429  case DevFmtX71:
430  Device->NumChan = 7;
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";
446  break;
447  }
448  if(layoutname && Device->Type != Loopback)
449  SetSpeakerArrangement(layoutname, SpeakerAngle, Speaker2Chan, Device->NumChan);
450 }
int ConfigValueStr(const char *blockName, const char *keyName, const char **ret)
Definition: alcConfig.c:316
GLuint const GLfloat * val
Definition: glew.h:2715
#define F_PI
Definition: alu.h:16
void ALvoid
Definition: al.h:74
enum DeviceType Type
Definition: alMain.h:565
static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MaxChannels], enum Channel Speaker2Chan[MaxChannels], ALint chans)
Definition: panning.c:34
char * strdup(const char *inStr)
Definition: strdup.c:6
#define NULL
Definition: ftobjs.h:61
GLclampf f
Definition: glew.h:3390
static __inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
Definition: alu.h:90
GLdouble angle
Definition: glew.h:8396
SDL_EventEntry * free
Definition: SDL_events.c:80
int ALint
Definition: al.h:56
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:8736
EGLImageKHR EGLint * name
Definition: eglext.h:284
const GLubyte GLuint GLuint GLuint GLuint alpha GLboolean GLboolean GLboolean GLboolean alpha GLint GLint GLsizei GLsizei GLenum type GLenum GLint GLenum GLint GLint GLsizei GLsizei GLint border GLenum GLint GLint GLint GLint GLint GLsizei GLsizei height GLsizei GLsizei GLenum GLenum const GLvoid *pixels GLenum GLint GLint i2
Definition: SDL_glfuncs.h:118
float ALfloat
Definition: al.h:68
ALfloat SpeakerAngle[MaxChannels]
Definition: alMain.h:610
ALuint NumChan
Definition: alMain.h:611
enum Channel Speaker2Chan[MaxChannels]
Definition: alMain.h:609
ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat *gains)
Definition: panning.c:149
unsigned int ALuint
Definition: al.h:59
enum DevFmtChannels FmtChans
Definition: alMain.h:572
#define ERR(...)
Definition: alMain.h:816
ALvoid aluInitPanning(ALCdevice *Device)
Definition: panning.c:343
GLuint GLuint end
Definition: glew.h:1239
#define str(s)
#define min(x, y)
Definition: os.h:75
int i
Definition: pngrutil.c:1377
Channel
Definition: alMain.h:480