alAuxEffectSlot.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 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 <stdlib.h>
  22. #include <math.h>
  23. #include "AL/al.h"
  24. #include "AL/alc.h"
  25. #include "alMain.h"
  26. #include "alAuxEffectSlot.h"
  27. #include "alThunk.h"
  28. #include "alError.h"
  29. #include "alSource.h"
  30. static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
  31. #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
  32. #define LookupEffect(m, k) ((ALeffect*)LookupUIntMapKey(&(m), (k)))
  33. AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
  34. {
  35. ALCcontext *Context;
  36. ALsizei i=0, j;
  37. Context = GetContextSuspended();
  38. if(!Context) return;
  39. if(n > 0)
  40. {
  41. ALCdevice *Device = Context->Device;
  42. if(Context->EffectSlotMap.size+n <= (ALsizei)Device->AuxiliaryEffectSlotMax)
  43. {
  44. // Check that enough memory has been allocted in the 'effectslots' array for n Effect Slots
  45. if(!IsBadWritePtr((void*)effectslots, n * sizeof(ALuint)))
  46. {
  47. ALenum err;
  48. while(i < n)
  49. {
  50. ALeffectslot *slot = calloc(1, sizeof(ALeffectslot));
  51. if(!slot || !(slot->EffectState=NoneCreate()))
  52. {
  53. free(slot);
  54. // We must have run out or memory
  55. alSetError(Context, AL_OUT_OF_MEMORY);
  56. alDeleteAuxiliaryEffectSlots(i, effectslots);
  57. break;
  58. }
  59. slot->effectslot = (ALuint)ALTHUNK_ADDENTRY(slot);
  60. err = InsertUIntMapEntry(&Context->EffectSlotMap,
  61. slot->effectslot, slot);
  62. if(err != AL_NO_ERROR)
  63. {
  64. ALTHUNK_REMOVEENTRY(slot->effectslot);
  65. ALEffect_Destroy(slot->EffectState);
  66. free(slot);
  67. alSetError(Context, err);
  68. alDeleteAuxiliaryEffectSlots(i, effectslots);
  69. break;
  70. }
  71. effectslots[i++] = slot->effectslot;
  72. slot->Gain = 1.0;
  73. slot->AuxSendAuto = AL_TRUE;
  74. for(j = 0;j < BUFFERSIZE;j++)
  75. slot->WetBuffer[j] = 0.0f;
  76. slot->refcount = 0;
  77. }
  78. }
  79. }
  80. else
  81. alSetError(Context, AL_INVALID_OPERATION);
  82. }
  83. ProcessContext(Context);
  84. }
  85. AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
  86. {
  87. ALCcontext *Context;
  88. ALeffectslot *EffectSlot;
  89. ALsizei i;
  90. Context = GetContextSuspended();
  91. if(!Context) return;
  92. if (n >= 0)
  93. {
  94. // Check that all effectslots are valid
  95. for (i = 0; i < n; i++)
  96. {
  97. if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslots[i])) == NULL)
  98. {
  99. alSetError(Context, AL_INVALID_NAME);
  100. break;
  101. }
  102. else
  103. {
  104. if(EffectSlot->refcount > 0)
  105. {
  106. alSetError(Context, AL_INVALID_NAME);
  107. break;
  108. }
  109. }
  110. }
  111. if (i == n)
  112. {
  113. // All effectslots are valid
  114. for (i = 0; i < n; i++)
  115. {
  116. // Recheck that the effectslot is valid, because there could be duplicated names
  117. if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslots[i])) != NULL)
  118. {
  119. ALEffect_Destroy(EffectSlot->EffectState);
  120. RemoveUIntMapKey(&Context->EffectSlotMap, EffectSlot->effectslot);
  121. ALTHUNK_REMOVEENTRY(EffectSlot->effectslot);
  122. memset(EffectSlot, 0, sizeof(ALeffectslot));
  123. free(EffectSlot);
  124. }
  125. }
  126. }
  127. }
  128. else
  129. alSetError(Context, AL_INVALID_VALUE);
  130. ProcessContext(Context);
  131. }
  132. AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
  133. {
  134. ALCcontext *Context;
  135. ALboolean result;
  136. Context = GetContextSuspended();
  137. if(!Context) return AL_FALSE;
  138. result = (LookupEffectSlot(Context->EffectSlotMap, effectslot) ?
  139. AL_TRUE : AL_FALSE);
  140. ProcessContext(Context);
  141. return result;
  142. }
  143. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
  144. {
  145. ALCcontext *Context;
  146. ALboolean updateSources = AL_FALSE;
  147. ALeffectslot *EffectSlot;
  148. Context = GetContextSuspended();
  149. if(!Context) return;
  150. if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
  151. {
  152. switch(param)
  153. {
  154. case AL_EFFECTSLOT_EFFECT: {
  155. ALeffect *effect = NULL;
  156. if(iValue == 0 ||
  157. (effect=LookupEffect(Context->Device->EffectMap, iValue)) != NULL)
  158. {
  159. InitializeEffect(Context, EffectSlot, effect);
  160. updateSources = AL_TRUE;
  161. }
  162. else
  163. alSetError(Context, AL_INVALID_VALUE);
  164. } break;
  165. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  166. if(iValue == AL_TRUE || iValue == AL_FALSE)
  167. {
  168. EffectSlot->AuxSendAuto = iValue;
  169. updateSources = AL_TRUE;
  170. }
  171. else
  172. alSetError(Context, AL_INVALID_VALUE);
  173. break;
  174. default:
  175. alSetError(Context, AL_INVALID_ENUM);
  176. break;
  177. }
  178. }
  179. else
  180. alSetError(Context, AL_INVALID_NAME);
  181. // Force updating the sources that use this slot, since it affects the
  182. // sending parameters
  183. if(updateSources)
  184. {
  185. ALsizei pos;
  186. for(pos = 0;pos < Context->SourceMap.size;pos++)
  187. {
  188. ALsource *source = Context->SourceMap.array[pos].value;
  189. ALuint i;
  190. for(i = 0;i < MAX_SENDS;i++)
  191. {
  192. if(!source->Send[i].Slot ||
  193. source->Send[i].Slot->effectslot != effectslot)
  194. continue;
  195. source->NeedsUpdate = AL_TRUE;
  196. break;
  197. }
  198. }
  199. }
  200. ProcessContext(Context);
  201. }
  202. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
  203. {
  204. ALCcontext *Context;
  205. Context = GetContextSuspended();
  206. if(!Context) return;
  207. if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
  208. {
  209. switch(param)
  210. {
  211. case AL_EFFECTSLOT_EFFECT:
  212. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  213. alAuxiliaryEffectSloti(effectslot, param, piValues[0]);
  214. break;
  215. default:
  216. alSetError(Context, AL_INVALID_ENUM);
  217. break;
  218. }
  219. }
  220. else
  221. alSetError(Context, AL_INVALID_NAME);
  222. ProcessContext(Context);
  223. }
  224. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
  225. {
  226. ALCcontext *Context;
  227. ALeffectslot *EffectSlot;
  228. Context = GetContextSuspended();
  229. if(!Context) return;
  230. if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
  231. {
  232. switch(param)
  233. {
  234. case AL_EFFECTSLOT_GAIN:
  235. if(flValue >= 0.0f && flValue <= 1.0f)
  236. EffectSlot->Gain = flValue;
  237. else
  238. alSetError(Context, AL_INVALID_VALUE);
  239. break;
  240. default:
  241. alSetError(Context, AL_INVALID_ENUM);
  242. break;
  243. }
  244. }
  245. else
  246. alSetError(Context, AL_INVALID_NAME);
  247. ProcessContext(Context);
  248. }
  249. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
  250. {
  251. ALCcontext *Context;
  252. Context = GetContextSuspended();
  253. if(!Context) return;
  254. if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
  255. {
  256. switch(param)
  257. {
  258. case AL_EFFECTSLOT_GAIN:
  259. alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]);
  260. break;
  261. default:
  262. alSetError(Context, AL_INVALID_ENUM);
  263. break;
  264. }
  265. }
  266. else
  267. alSetError(Context, AL_INVALID_NAME);
  268. ProcessContext(Context);
  269. }
  270. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
  271. {
  272. ALCcontext *Context;
  273. ALeffectslot *EffectSlot;
  274. Context = GetContextSuspended();
  275. if(!Context) return;
  276. if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
  277. {
  278. switch(param)
  279. {
  280. case AL_EFFECTSLOT_EFFECT:
  281. *piValue = EffectSlot->effect.effect;
  282. break;
  283. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  284. *piValue = EffectSlot->AuxSendAuto;
  285. break;
  286. default:
  287. alSetError(Context, AL_INVALID_ENUM);
  288. break;
  289. }
  290. }
  291. else
  292. alSetError(Context, AL_INVALID_NAME);
  293. ProcessContext(Context);
  294. }
  295. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
  296. {
  297. ALCcontext *Context;
  298. Context = GetContextSuspended();
  299. if(!Context) return;
  300. if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
  301. {
  302. switch(param)
  303. {
  304. case AL_EFFECTSLOT_EFFECT:
  305. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  306. alGetAuxiliaryEffectSloti(effectslot, param, piValues);
  307. break;
  308. default:
  309. alSetError(Context, AL_INVALID_ENUM);
  310. break;
  311. }
  312. }
  313. else
  314. alSetError(Context, AL_INVALID_NAME);
  315. ProcessContext(Context);
  316. }
  317. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
  318. {
  319. ALCcontext *Context;
  320. ALeffectslot *EffectSlot;
  321. Context = GetContextSuspended();
  322. if(!Context) return;
  323. if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
  324. {
  325. switch(param)
  326. {
  327. case AL_EFFECTSLOT_GAIN:
  328. *pflValue = EffectSlot->Gain;
  329. break;
  330. default:
  331. alSetError(Context, AL_INVALID_ENUM);
  332. break;
  333. }
  334. }
  335. else
  336. alSetError(Context, AL_INVALID_NAME);
  337. ProcessContext(Context);
  338. }
  339. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
  340. {
  341. ALCcontext *Context;
  342. Context = GetContextSuspended();
  343. if(!Context) return;
  344. if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
  345. {
  346. switch(param)
  347. {
  348. case AL_EFFECTSLOT_GAIN:
  349. alGetAuxiliaryEffectSlotf(effectslot, param, pflValues);
  350. break;
  351. default:
  352. alSetError(Context, AL_INVALID_ENUM);
  353. break;
  354. }
  355. }
  356. else
  357. alSetError(Context, AL_INVALID_NAME);
  358. ProcessContext(Context);
  359. }
  360. static ALvoid NoneDestroy(ALeffectState *State)
  361. { free(State); }
  362. static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device)
  363. {
  364. return AL_TRUE;
  365. (void)State;
  366. (void)Device;
  367. }
  368. static ALvoid NoneUpdate(ALeffectState *State, ALCcontext *Context, const ALeffect *Effect)
  369. {
  370. (void)State;
  371. (void)Context;
  372. (void)Effect;
  373. }
  374. static ALvoid NoneProcess(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
  375. {
  376. (void)State;
  377. (void)Slot;
  378. (void)SamplesToDo;
  379. (void)SamplesIn;
  380. (void)SamplesOut;
  381. }
  382. ALeffectState *NoneCreate(void)
  383. {
  384. ALeffectState *state;
  385. state = calloc(1, sizeof(*state));
  386. if(!state)
  387. return NULL;
  388. state->Destroy = NoneDestroy;
  389. state->DeviceUpdate = NoneDeviceUpdate;
  390. state->Update = NoneUpdate;
  391. state->Process = NoneProcess;
  392. return state;
  393. }
  394. static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
  395. {
  396. if(EffectSlot->effect.type != (effect?effect->type:AL_EFFECT_NULL))
  397. {
  398. ALeffectState *NewState = NULL;
  399. if(!effect || effect->type == AL_EFFECT_NULL)
  400. NewState = NoneCreate();
  401. else if(effect->type == AL_EFFECT_EAXREVERB)
  402. NewState = EAXVerbCreate();
  403. else if(effect->type == AL_EFFECT_REVERB)
  404. NewState = VerbCreate();
  405. else if(effect->type == AL_EFFECT_ECHO)
  406. NewState = EchoCreate();
  407. else if(effect->type == AL_EFFECT_RING_MODULATOR)
  408. NewState = ModulatorCreate();
  409. /* No new state? An error occured.. */
  410. if(NewState == NULL ||
  411. ALEffect_DeviceUpdate(NewState, Context->Device) == AL_FALSE)
  412. {
  413. if(NewState)
  414. ALEffect_Destroy(NewState);
  415. alSetError(Context, AL_OUT_OF_MEMORY);
  416. return;
  417. }
  418. if(EffectSlot->EffectState)
  419. ALEffect_Destroy(EffectSlot->EffectState);
  420. EffectSlot->EffectState = NewState;
  421. }
  422. if(!effect)
  423. memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
  424. else
  425. memcpy(&EffectSlot->effect, effect, sizeof(*effect));
  426. ALEffect_Update(EffectSlot->EffectState, Context, effect);
  427. }
  428. ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
  429. {
  430. ALsizei pos;
  431. for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
  432. {
  433. ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
  434. Context->EffectSlotMap.array[pos].value = NULL;
  435. // Release effectslot structure
  436. ALEffect_Destroy(temp->EffectState);
  437. ALTHUNK_REMOVEENTRY(temp->effectslot);
  438. memset(temp, 0, sizeof(ALeffectslot));
  439. free(temp);
  440. }
  441. }