panning.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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. extern inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels]);
  31. static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MaxChannels],
  32. enum Channel Speaker2Chan[MaxChannels], ALint chans)
  33. {
  34. char *confkey, *next;
  35. char *layout_str;
  36. char *sep, *end;
  37. enum Channel val;
  38. const char *str;
  39. int i;
  40. if(!ConfigValueStr(NULL, name, &str) && !ConfigValueStr(NULL, "layout", &str))
  41. return;
  42. layout_str = strdup(str);
  43. next = confkey = layout_str;
  44. while(next && *next)
  45. {
  46. confkey = next;
  47. next = strchr(confkey, ',');
  48. if(next)
  49. {
  50. *next = 0;
  51. do {
  52. next++;
  53. } while(isspace(*next) || *next == ',');
  54. }
  55. sep = strchr(confkey, '=');
  56. if(!sep || confkey == sep)
  57. {
  58. ERR("Malformed speaker key: %s\n", confkey);
  59. continue;
  60. }
  61. end = sep - 1;
  62. while(isspace(*end) && end != confkey)
  63. end--;
  64. *(++end) = 0;
  65. if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
  66. val = FrontLeft;
  67. else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
  68. val = FrontRight;
  69. else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
  70. val = FrontCenter;
  71. else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
  72. val = BackLeft;
  73. else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
  74. val = BackRight;
  75. else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
  76. val = BackCenter;
  77. else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
  78. val = SideLeft;
  79. else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
  80. val = SideRight;
  81. else
  82. {
  83. ERR("Unknown speaker for %s: \"%s\"\n", name, confkey);
  84. continue;
  85. }
  86. *(sep++) = 0;
  87. while(isspace(*sep))
  88. sep++;
  89. for(i = 0;i < chans;i++)
  90. {
  91. if(Speaker2Chan[i] == val)
  92. {
  93. long angle = strtol(sep, NULL, 10);
  94. if(angle >= -180 && angle <= 180)
  95. SpeakerAngle[i] = DEG2RAD(angle);
  96. else
  97. ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
  98. break;
  99. }
  100. }
  101. }
  102. free(layout_str);
  103. layout_str = NULL;
  104. for(i = 0;i < chans;i++)
  105. {
  106. int min = i;
  107. int i2;
  108. for(i2 = i+1;i2 < chans;i2++)
  109. {
  110. if(SpeakerAngle[i2] < SpeakerAngle[min])
  111. min = i2;
  112. }
  113. if(min != i)
  114. {
  115. ALfloat tmpf;
  116. enum Channel tmpc;
  117. tmpf = SpeakerAngle[i];
  118. SpeakerAngle[i] = SpeakerAngle[min];
  119. SpeakerAngle[min] = tmpf;
  120. tmpc = Speaker2Chan[i];
  121. Speaker2Chan[i] = Speaker2Chan[min];
  122. Speaker2Chan[min] = tmpc;
  123. }
  124. }
  125. }
  126. void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels])
  127. {
  128. ALfloat tmpgains[MaxChannels] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
  129. enum Channel Speaker2Chan[MaxChannels];
  130. ALfloat SpeakerAngle[MaxChannels];
  131. ALfloat langle, rangle;
  132. ALfloat a;
  133. ALuint i;
  134. for(i = 0;i < device->NumChan;i++)
  135. Speaker2Chan[i] = device->Speaker2Chan[i];
  136. for(i = 0;i < device->NumChan;i++)
  137. SpeakerAngle[i] = device->SpeakerAngle[i];
  138. /* Some easy special-cases first... */
  139. if(device->NumChan <= 1 || hwidth >= F_PI)
  140. {
  141. /* Full coverage for all speakers. */
  142. for(i = 0;i < MaxChannels;i++)
  143. gains[i] = 0.0f;
  144. for(i = 0;i < device->NumChan;i++)
  145. {
  146. enum Channel chan = Speaker2Chan[i];
  147. gains[chan] = ingain;
  148. }
  149. return;
  150. }
  151. if(hwidth <= 0.0f)
  152. {
  153. /* Infinitely small sound point. */
  154. for(i = 0;i < MaxChannels;i++)
  155. gains[i] = 0.0f;
  156. for(i = 0;i < device->NumChan-1;i++)
  157. {
  158. if(angle >= SpeakerAngle[i] && angle < SpeakerAngle[i+1])
  159. {
  160. /* Sound is between speakers i and i+1 */
  161. a = (angle-SpeakerAngle[i]) /
  162. (SpeakerAngle[i+1]-SpeakerAngle[i]);
  163. gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain;
  164. gains[Speaker2Chan[i+1]] = sqrtf( a) * ingain;
  165. return;
  166. }
  167. }
  168. /* Sound is between last and first speakers */
  169. if(angle < SpeakerAngle[0])
  170. angle += F_2PI;
  171. a = (angle-SpeakerAngle[i]) /
  172. (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
  173. gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain;
  174. gains[Speaker2Chan[0]] = sqrtf( a) * ingain;
  175. return;
  176. }
  177. if(fabsf(angle)+hwidth > F_PI)
  178. {
  179. /* The coverage area would go outside of -pi...+pi. Instead, rotate the
  180. * speaker angles so it would be as if angle=0, and keep them wrapped
  181. * within -pi...+pi. */
  182. if(angle > 0.0f)
  183. {
  184. ALuint done;
  185. ALuint i = 0;
  186. while(i < device->NumChan && device->SpeakerAngle[i]-angle < -F_PI)
  187. i++;
  188. for(done = 0;i < device->NumChan;done++)
  189. {
  190. SpeakerAngle[done] = device->SpeakerAngle[i]-angle;
  191. Speaker2Chan[done] = device->Speaker2Chan[i];
  192. i++;
  193. }
  194. for(i = 0;done < device->NumChan;i++)
  195. {
  196. SpeakerAngle[done] = device->SpeakerAngle[i]-angle + F_2PI;
  197. Speaker2Chan[done] = device->Speaker2Chan[i];
  198. done++;
  199. }
  200. }
  201. else
  202. {
  203. /* NOTE: '< device->NumChan' on the iterators is correct here since
  204. * we need to handle index 0. Because the iterators are unsigned,
  205. * they'll underflow and wrap to become 0xFFFFFFFF, which will
  206. * break as expected. */
  207. ALuint done;
  208. ALuint i = device->NumChan-1;
  209. while(i < device->NumChan && device->SpeakerAngle[i]-angle > F_PI)
  210. i--;
  211. for(done = device->NumChan-1;i < device->NumChan;done--)
  212. {
  213. SpeakerAngle[done] = device->SpeakerAngle[i]-angle;
  214. Speaker2Chan[done] = device->Speaker2Chan[i];
  215. i--;
  216. }
  217. for(i = device->NumChan-1;done < device->NumChan;i--)
  218. {
  219. SpeakerAngle[done] = device->SpeakerAngle[i]-angle - F_2PI;
  220. Speaker2Chan[done] = device->Speaker2Chan[i];
  221. done--;
  222. }
  223. }
  224. angle = 0.0f;
  225. }
  226. langle = angle - hwidth;
  227. rangle = angle + hwidth;
  228. /* First speaker */
  229. i = 0;
  230. do {
  231. ALuint last = device->NumChan-1;
  232. enum Channel chan = Speaker2Chan[i];
  233. if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
  234. {
  235. tmpgains[chan] = 1.0f;
  236. continue;
  237. }
  238. if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
  239. {
  240. a = (langle-SpeakerAngle[i]) /
  241. (SpeakerAngle[i+1]-SpeakerAngle[i]);
  242. tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
  243. }
  244. if(SpeakerAngle[i] > rangle)
  245. {
  246. a = (F_2PI + rangle-SpeakerAngle[last]) /
  247. (F_2PI + SpeakerAngle[i]-SpeakerAngle[last]);
  248. tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
  249. }
  250. else if(SpeakerAngle[last] < rangle)
  251. {
  252. a = (rangle-SpeakerAngle[last]) /
  253. (F_2PI + SpeakerAngle[i]-SpeakerAngle[last]);
  254. tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
  255. }
  256. } while(0);
  257. for(i = 1;i < device->NumChan-1;i++)
  258. {
  259. enum Channel chan = Speaker2Chan[i];
  260. if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
  261. {
  262. tmpgains[chan] = 1.0f;
  263. continue;
  264. }
  265. if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
  266. {
  267. a = (langle-SpeakerAngle[i]) /
  268. (SpeakerAngle[i+1]-SpeakerAngle[i]);
  269. tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
  270. }
  271. if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
  272. {
  273. a = (rangle-SpeakerAngle[i-1]) /
  274. (SpeakerAngle[i]-SpeakerAngle[i-1]);
  275. tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
  276. }
  277. }
  278. /* Last speaker */
  279. i = device->NumChan-1;
  280. do {
  281. enum Channel chan = Speaker2Chan[i];
  282. if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
  283. {
  284. tmpgains[Speaker2Chan[i]] = 1.0f;
  285. continue;
  286. }
  287. if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
  288. {
  289. a = (rangle-SpeakerAngle[i-1]) /
  290. (SpeakerAngle[i]-SpeakerAngle[i-1]);
  291. tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
  292. }
  293. if(SpeakerAngle[i] < langle)
  294. {
  295. a = (langle-SpeakerAngle[i]) /
  296. (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
  297. tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
  298. }
  299. else if(SpeakerAngle[0] > langle)
  300. {
  301. a = (F_2PI + langle-SpeakerAngle[i]) /
  302. (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
  303. tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
  304. }
  305. } while(0);
  306. for(i = 0;i < device->NumChan;i++)
  307. {
  308. enum Channel chan = device->Speaker2Chan[i];
  309. gains[chan] = sqrtf(tmpgains[chan]) * ingain;
  310. }
  311. }
  312. ALvoid aluInitPanning(ALCdevice *Device)
  313. {
  314. const char *layoutname = NULL;
  315. enum Channel *Speaker2Chan;
  316. ALfloat *SpeakerAngle;
  317. Speaker2Chan = Device->Speaker2Chan;
  318. SpeakerAngle = Device->SpeakerAngle;
  319. switch(Device->FmtChans)
  320. {
  321. case DevFmtMono:
  322. Device->NumChan = 1;
  323. Speaker2Chan[0] = FrontCenter;
  324. SpeakerAngle[0] = DEG2RAD(0.0f);
  325. layoutname = NULL;
  326. break;
  327. case DevFmtStereo:
  328. Device->NumChan = 2;
  329. Speaker2Chan[0] = FrontLeft;
  330. Speaker2Chan[1] = FrontRight;
  331. SpeakerAngle[0] = DEG2RAD(-90.0f);
  332. SpeakerAngle[1] = DEG2RAD( 90.0f);
  333. layoutname = "layout_stereo";
  334. break;
  335. case DevFmtQuad:
  336. Device->NumChan = 4;
  337. Speaker2Chan[0] = BackLeft;
  338. Speaker2Chan[1] = FrontLeft;
  339. Speaker2Chan[2] = FrontRight;
  340. Speaker2Chan[3] = BackRight;
  341. SpeakerAngle[0] = DEG2RAD(-135.0f);
  342. SpeakerAngle[1] = DEG2RAD( -45.0f);
  343. SpeakerAngle[2] = DEG2RAD( 45.0f);
  344. SpeakerAngle[3] = DEG2RAD( 135.0f);
  345. layoutname = "layout_quad";
  346. break;
  347. case DevFmtX51:
  348. Device->NumChan = 5;
  349. Speaker2Chan[0] = BackLeft;
  350. Speaker2Chan[1] = FrontLeft;
  351. Speaker2Chan[2] = FrontCenter;
  352. Speaker2Chan[3] = FrontRight;
  353. Speaker2Chan[4] = BackRight;
  354. SpeakerAngle[0] = DEG2RAD(-110.0f);
  355. SpeakerAngle[1] = DEG2RAD( -30.0f);
  356. SpeakerAngle[2] = DEG2RAD( 0.0f);
  357. SpeakerAngle[3] = DEG2RAD( 30.0f);
  358. SpeakerAngle[4] = DEG2RAD( 110.0f);
  359. layoutname = "layout_surround51";
  360. break;
  361. case DevFmtX51Side:
  362. Device->NumChan = 5;
  363. Speaker2Chan[0] = SideLeft;
  364. Speaker2Chan[1] = FrontLeft;
  365. Speaker2Chan[2] = FrontCenter;
  366. Speaker2Chan[3] = FrontRight;
  367. Speaker2Chan[4] = SideRight;
  368. SpeakerAngle[0] = DEG2RAD(-90.0f);
  369. SpeakerAngle[1] = DEG2RAD(-30.0f);
  370. SpeakerAngle[2] = DEG2RAD( 0.0f);
  371. SpeakerAngle[3] = DEG2RAD( 30.0f);
  372. SpeakerAngle[4] = DEG2RAD( 90.0f);
  373. layoutname = "layout_side51";
  374. break;
  375. case DevFmtX61:
  376. Device->NumChan = 6;
  377. Speaker2Chan[0] = SideLeft;
  378. Speaker2Chan[1] = FrontLeft;
  379. Speaker2Chan[2] = FrontCenter;
  380. Speaker2Chan[3] = FrontRight;
  381. Speaker2Chan[4] = SideRight;
  382. Speaker2Chan[5] = BackCenter;
  383. SpeakerAngle[0] = DEG2RAD(-90.0f);
  384. SpeakerAngle[1] = DEG2RAD(-30.0f);
  385. SpeakerAngle[2] = DEG2RAD( 0.0f);
  386. SpeakerAngle[3] = DEG2RAD( 30.0f);
  387. SpeakerAngle[4] = DEG2RAD( 90.0f);
  388. SpeakerAngle[5] = DEG2RAD(180.0f);
  389. layoutname = "layout_surround61";
  390. break;
  391. case DevFmtX71:
  392. Device->NumChan = 7;
  393. Speaker2Chan[0] = BackLeft;
  394. Speaker2Chan[1] = SideLeft;
  395. Speaker2Chan[2] = FrontLeft;
  396. Speaker2Chan[3] = FrontCenter;
  397. Speaker2Chan[4] = FrontRight;
  398. Speaker2Chan[5] = SideRight;
  399. Speaker2Chan[6] = BackRight;
  400. SpeakerAngle[0] = DEG2RAD(-150.0f);
  401. SpeakerAngle[1] = DEG2RAD( -90.0f);
  402. SpeakerAngle[2] = DEG2RAD( -30.0f);
  403. SpeakerAngle[3] = DEG2RAD( 0.0f);
  404. SpeakerAngle[4] = DEG2RAD( 30.0f);
  405. SpeakerAngle[5] = DEG2RAD( 90.0f);
  406. SpeakerAngle[6] = DEG2RAD( 150.0f);
  407. layoutname = "layout_surround71";
  408. break;
  409. }
  410. if(layoutname && Device->Type != Loopback)
  411. SetSpeakerArrangement(layoutname, SpeakerAngle, Speaker2Chan, Device->NumChan);
  412. }