panning.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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.
  8. *
  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.
  13. *
  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
  19. */
  20. #include "config.h"
  21. #include <math.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. #include <assert.h>
  26. #include "alMain.h"
  27. #include "AL/al.h"
  28. #include "AL/alc.h"
  29. #include "alu.h"
  30. static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MAXCHANNELS],
  31. enum Channel Speaker2Chan[MAXCHANNELS], ALint chans)
  32. {
  33. char *confkey, *next;
  34. char *layout_str;
  35. char *sep, *end;
  36. enum Channel val;
  37. const char *str;
  38. int i;
  39. if(!ConfigValueStr(NULL, name, &str) && !ConfigValueStr(NULL, "layout", &str))
  40. return;
  41. layout_str = strdup(str);
  42. next = confkey = layout_str;
  43. while(next && *next)
  44. {
  45. confkey = next;
  46. next = strchr(confkey, ',');
  47. if(next)
  48. {
  49. *next = 0;
  50. do {
  51. next++;
  52. } while(isspace(*next) || *next == ',');
  53. }
  54. sep = strchr(confkey, '=');
  55. if(!sep || confkey == sep)
  56. {
  57. ERR("Malformed speaker key: %s\n", confkey);
  58. continue;
  59. }
  60. end = sep - 1;
  61. while(isspace(*end) && end != confkey)
  62. end--;
  63. *(++end) = 0;
  64. if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
  65. val = FRONT_LEFT;
  66. else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
  67. val = FRONT_RIGHT;
  68. else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
  69. val = FRONT_CENTER;
  70. else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
  71. val = BACK_LEFT;
  72. else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
  73. val = BACK_RIGHT;
  74. else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
  75. val = BACK_CENTER;
  76. else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
  77. val = SIDE_LEFT;
  78. else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
  79. val = SIDE_RIGHT;
  80. else
  81. {
  82. ERR("Unknown speaker for %s: \"%s\"\n", name, confkey);
  83. continue;
  84. }
  85. *(sep++) = 0;
  86. while(isspace(*sep))
  87. sep++;
  88. for(i = 0;i < chans;i++)
  89. {
  90. if(Speaker2Chan[i] == val)
  91. {
  92. long angle = strtol(sep, NULL, 10);
  93. if(angle >= -180 && angle <= 180)
  94. SpeakerAngle[i] = angle * F_PI/180.0f;
  95. else
  96. ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
  97. break;
  98. }
  99. }
  100. }
  101. free(layout_str);
  102. layout_str = NULL;
  103. for(i = 0;i < chans;i++)
  104. {
  105. int min = i;
  106. int i2;
  107. for(i2 = i+1;i2 < chans;i2++)
  108. {
  109. if(SpeakerAngle[i2] < SpeakerAngle[min])
  110. min = i2;
  111. }
  112. if(min != i)
  113. {
  114. ALfloat tmpf;
  115. enum Channel tmpc;
  116. tmpf = SpeakerAngle[i];
  117. SpeakerAngle[i] = SpeakerAngle[min];
  118. SpeakerAngle[min] = tmpf;
  119. tmpc = Speaker2Chan[i];
  120. Speaker2Chan[i] = Speaker2Chan[min];
  121. Speaker2Chan[min] = tmpc;
  122. }
  123. }
  124. }
  125. static ALfloat aluLUTpos2Angle(ALint pos)
  126. {
  127. if(pos < QUADRANT_NUM)
  128. return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos));
  129. if(pos < 2 * QUADRANT_NUM)
  130. return F_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos));
  131. if(pos < 3 * QUADRANT_NUM)
  132. return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - F_PI;
  133. return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - F_PI_2;
  134. }
  135. ALint aluCart2LUTpos(ALfloat re, ALfloat im)
  136. {
  137. ALint pos = 0;
  138. ALfloat denom = aluFabs(re) + aluFabs(im);
  139. if(denom > 0.0f)
  140. pos = (ALint)(QUADRANT_NUM*aluFabs(im) / denom + 0.5);
  141. if(re < 0.0f)
  142. pos = 2 * QUADRANT_NUM - pos;
  143. if(im < 0.0f)
  144. pos = LUT_NUM - pos;
  145. return pos%LUT_NUM;
  146. }
  147. ALvoid aluInitPanning(ALCdevice *Device)
  148. {
  149. ALfloat SpeakerAngle[MAXCHANNELS];
  150. const char *layoutname = NULL;
  151. enum Channel *Speaker2Chan;
  152. ALfloat Alpha, Theta;
  153. ALint pos;
  154. ALuint s;
  155. Speaker2Chan = Device->Speaker2Chan;
  156. switch(Device->FmtChans)
  157. {
  158. case DevFmtMono:
  159. Device->NumChan = 1;
  160. Speaker2Chan[0] = FRONT_CENTER;
  161. SpeakerAngle[0] = F_PI/180.0f * 0.0f;
  162. layoutname = NULL;
  163. break;
  164. case DevFmtStereo:
  165. Device->NumChan = 2;
  166. Speaker2Chan[0] = FRONT_LEFT;
  167. Speaker2Chan[1] = FRONT_RIGHT;
  168. SpeakerAngle[0] = F_PI/180.0f * -90.0f;
  169. SpeakerAngle[1] = F_PI/180.0f * 90.0f;
  170. layoutname = "layout_stereo";
  171. break;
  172. case DevFmtQuad:
  173. Device->NumChan = 4;
  174. Speaker2Chan[0] = BACK_LEFT;
  175. Speaker2Chan[1] = FRONT_LEFT;
  176. Speaker2Chan[2] = FRONT_RIGHT;
  177. Speaker2Chan[3] = BACK_RIGHT;
  178. SpeakerAngle[0] = F_PI/180.0f * -135.0f;
  179. SpeakerAngle[1] = F_PI/180.0f * -45.0f;
  180. SpeakerAngle[2] = F_PI/180.0f * 45.0f;
  181. SpeakerAngle[3] = F_PI/180.0f * 135.0f;
  182. layoutname = "layout_quad";
  183. break;
  184. case DevFmtX51:
  185. Device->NumChan = 5;
  186. Speaker2Chan[0] = BACK_LEFT;
  187. Speaker2Chan[1] = FRONT_LEFT;
  188. Speaker2Chan[2] = FRONT_CENTER;
  189. Speaker2Chan[3] = FRONT_RIGHT;
  190. Speaker2Chan[4] = BACK_RIGHT;
  191. SpeakerAngle[0] = F_PI/180.0f * -110.0f;
  192. SpeakerAngle[1] = F_PI/180.0f * -30.0f;
  193. SpeakerAngle[2] = F_PI/180.0f * 0.0f;
  194. SpeakerAngle[3] = F_PI/180.0f * 30.0f;
  195. SpeakerAngle[4] = F_PI/180.0f * 110.0f;
  196. layoutname = "layout_surround51";
  197. break;
  198. case DevFmtX51Side:
  199. Device->NumChan = 5;
  200. Speaker2Chan[0] = SIDE_LEFT;
  201. Speaker2Chan[1] = FRONT_LEFT;
  202. Speaker2Chan[2] = FRONT_CENTER;
  203. Speaker2Chan[3] = FRONT_RIGHT;
  204. Speaker2Chan[4] = SIDE_RIGHT;
  205. SpeakerAngle[0] = F_PI/180.0f * -90.0f;
  206. SpeakerAngle[1] = F_PI/180.0f * -30.0f;
  207. SpeakerAngle[2] = F_PI/180.0f * 0.0f;
  208. SpeakerAngle[3] = F_PI/180.0f * 30.0f;
  209. SpeakerAngle[4] = F_PI/180.0f * 90.0f;
  210. layoutname = "layout_side51";
  211. break;
  212. case DevFmtX61:
  213. Device->NumChan = 6;
  214. Speaker2Chan[0] = SIDE_LEFT;
  215. Speaker2Chan[1] = FRONT_LEFT;
  216. Speaker2Chan[2] = FRONT_CENTER;
  217. Speaker2Chan[3] = FRONT_RIGHT;
  218. Speaker2Chan[4] = SIDE_RIGHT;
  219. Speaker2Chan[5] = BACK_CENTER;
  220. SpeakerAngle[0] = F_PI/180.0f * -90.0f;
  221. SpeakerAngle[1] = F_PI/180.0f * -30.0f;
  222. SpeakerAngle[2] = F_PI/180.0f * 0.0f;
  223. SpeakerAngle[3] = F_PI/180.0f * 30.0f;
  224. SpeakerAngle[4] = F_PI/180.0f * 90.0f;
  225. SpeakerAngle[5] = F_PI/180.0f * 180.0f;
  226. layoutname = "layout_surround61";
  227. break;
  228. case DevFmtX71:
  229. Device->NumChan = 7;
  230. Speaker2Chan[0] = BACK_LEFT;
  231. Speaker2Chan[1] = SIDE_LEFT;
  232. Speaker2Chan[2] = FRONT_LEFT;
  233. Speaker2Chan[3] = FRONT_CENTER;
  234. Speaker2Chan[4] = FRONT_RIGHT;
  235. Speaker2Chan[5] = SIDE_RIGHT;
  236. Speaker2Chan[6] = BACK_RIGHT;
  237. SpeakerAngle[0] = F_PI/180.0f * -150.0f;
  238. SpeakerAngle[1] = F_PI/180.0f * -90.0f;
  239. SpeakerAngle[2] = F_PI/180.0f * -30.0f;
  240. SpeakerAngle[3] = F_PI/180.0f * 0.0f;
  241. SpeakerAngle[4] = F_PI/180.0f * 30.0f;
  242. SpeakerAngle[5] = F_PI/180.0f * 90.0f;
  243. SpeakerAngle[6] = F_PI/180.0f * 150.0f;
  244. layoutname = "layout_surround71";
  245. break;
  246. }
  247. if(layoutname && Device->Type != Loopback)
  248. SetSpeakerArrangement(layoutname, SpeakerAngle, Speaker2Chan, Device->NumChan);
  249. for(pos = 0; pos < LUT_NUM; pos++)
  250. {
  251. ALfloat *PanningLUT = Device->PanningLUT[pos];
  252. /* clear all values */
  253. for(s = 0; s < MAXCHANNELS; s++)
  254. PanningLUT[s] = 0.0f;
  255. if(Device->NumChan == 1)
  256. {
  257. PanningLUT[Speaker2Chan[0]] = 1.0f;
  258. continue;
  259. }
  260. /* source angle */
  261. Theta = aluLUTpos2Angle(pos);
  262. /* set panning values */
  263. for(s = 0; s < Device->NumChan - 1; s++)
  264. {
  265. if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1])
  266. {
  267. /* source between speaker s and speaker s+1 */
  268. Alpha = (Theta-SpeakerAngle[s]) /
  269. (SpeakerAngle[s+1]-SpeakerAngle[s]);
  270. PanningLUT[Speaker2Chan[s]] = aluSqrt(1.0f-Alpha);
  271. PanningLUT[Speaker2Chan[s+1]] = aluSqrt( Alpha);
  272. break;
  273. }
  274. }
  275. if(s == Device->NumChan - 1)
  276. {
  277. /* source between last and first speaker */
  278. if(Theta < SpeakerAngle[0])
  279. Theta += F_PI*2.0f;
  280. Alpha = (Theta-SpeakerAngle[s]) /
  281. (F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[s]);
  282. PanningLUT[Speaker2Chan[s]] = aluSqrt(1.0f-Alpha);
  283. PanningLUT[Speaker2Chan[0]] = aluSqrt( Alpha);
  284. }
  285. }
  286. }