alAuxEffectSlot.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id);
  31. extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id);
  32. static ALenum AddEffectSlotArray(ALCcontext *Context, ALeffectslot **start, ALsizei count);
  33. static void RemoveEffectSlotArray(ALCcontext *Context, const ALeffectslot *slot);
  34. static UIntMap EffectStateFactoryMap;
  35. static inline ALeffectStateFactory *getFactoryByType(ALenum type)
  36. {
  37. ALeffectStateFactory* (*getFactory)(void) = LookupUIntMapKey(&EffectStateFactoryMap, type);
  38. if(getFactory != NULL)
  39. return getFactory();
  40. return NULL;
  41. }
  42. AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
  43. {
  44. ALCcontext *context;
  45. VECTOR(ALeffectslot*) slotvec;
  46. ALsizei cur;
  47. ALenum err;
  48. context = GetContextRef();
  49. if(!context) return;
  50. VECTOR_INIT(slotvec);
  51. if(!(n >= 0))
  52. SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
  53. if(!VECTOR_RESERVE(slotvec, n))
  54. SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
  55. for(cur = 0;cur < n;cur++)
  56. {
  57. ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
  58. err = AL_OUT_OF_MEMORY;
  59. if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
  60. {
  61. al_free(slot);
  62. alDeleteAuxiliaryEffectSlots(cur, effectslots);
  63. SET_ERROR_AND_GOTO(context, err, done);
  64. }
  65. err = NewThunkEntry(&slot->id);
  66. if(err == AL_NO_ERROR)
  67. err = InsertUIntMapEntry(&context->EffectSlotMap, slot->id, slot);
  68. if(err != AL_NO_ERROR)
  69. {
  70. FreeThunkEntry(slot->id);
  71. DELETE_OBJ(slot->EffectState);
  72. al_free(slot);
  73. alDeleteAuxiliaryEffectSlots(cur, effectslots);
  74. SET_ERROR_AND_GOTO(context, err, done);
  75. }
  76. VECTOR_PUSH_BACK(slotvec, slot);
  77. effectslots[cur] = slot->id;
  78. }
  79. err = AddEffectSlotArray(context, VECTOR_ITER_BEGIN(slotvec), n);
  80. if(err != AL_NO_ERROR)
  81. {
  82. alDeleteAuxiliaryEffectSlots(cur, effectslots);
  83. SET_ERROR_AND_GOTO(context, err, done);
  84. }
  85. done:
  86. VECTOR_DEINIT(slotvec);
  87. ALCcontext_DecRef(context);
  88. }
  89. AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
  90. {
  91. ALCcontext *context;
  92. ALeffectslot *slot;
  93. ALsizei i;
  94. context = GetContextRef();
  95. if(!context) return;
  96. if(!(n >= 0))
  97. SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
  98. for(i = 0;i < n;i++)
  99. {
  100. if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
  101. SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
  102. if(ReadRef(&slot->ref) != 0)
  103. SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
  104. }
  105. // All effectslots are valid
  106. for(i = 0;i < n;i++)
  107. {
  108. if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
  109. continue;
  110. FreeThunkEntry(slot->id);
  111. RemoveEffectSlotArray(context, slot);
  112. DELETE_OBJ(slot->EffectState);
  113. memset(slot, 0, sizeof(*slot));
  114. al_free(slot);
  115. }
  116. done:
  117. ALCcontext_DecRef(context);
  118. }
  119. AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
  120. {
  121. ALCcontext *context;
  122. ALboolean ret;
  123. context = GetContextRef();
  124. if(!context) return AL_FALSE;
  125. ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
  126. ALCcontext_DecRef(context);
  127. return ret;
  128. }
  129. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
  130. {
  131. ALCdevice *device;
  132. ALCcontext *context;
  133. ALeffectslot *slot;
  134. ALeffect *effect = NULL;
  135. ALenum err;
  136. context = GetContextRef();
  137. if(!context) return;
  138. device = context->Device;
  139. if((slot=LookupEffectSlot(context, effectslot)) == NULL)
  140. SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
  141. switch(param)
  142. {
  143. case AL_EFFECTSLOT_EFFECT:
  144. effect = (value ? LookupEffect(device, value) : NULL);
  145. if(!(value == 0 || effect != NULL))
  146. SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
  147. err = InitializeEffect(device, slot, effect);
  148. if(err != AL_NO_ERROR)
  149. SET_ERROR_AND_GOTO(context, err, done);
  150. ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
  151. break;
  152. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  153. if(!(value == AL_TRUE || value == AL_FALSE))
  154. SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
  155. slot->AuxSendAuto = value;
  156. ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
  157. break;
  158. default:
  159. SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
  160. }
  161. done:
  162. ALCcontext_DecRef(context);
  163. }
  164. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
  165. {
  166. ALCcontext *context;
  167. switch(param)
  168. {
  169. case AL_EFFECTSLOT_EFFECT:
  170. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  171. alAuxiliaryEffectSloti(effectslot, param, values[0]);
  172. return;
  173. }
  174. context = GetContextRef();
  175. if(!context) return;
  176. if(LookupEffectSlot(context, effectslot) == NULL)
  177. SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
  178. switch(param)
  179. {
  180. default:
  181. SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
  182. }
  183. done:
  184. ALCcontext_DecRef(context);
  185. }
  186. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
  187. {
  188. ALCcontext *context;
  189. ALeffectslot *slot;
  190. context = GetContextRef();
  191. if(!context) return;
  192. if((slot=LookupEffectSlot(context, effectslot)) == NULL)
  193. SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
  194. switch(param)
  195. {
  196. case AL_EFFECTSLOT_GAIN:
  197. if(!(value >= 0.0f && value <= 1.0f))
  198. SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
  199. slot->Gain = value;
  200. ATOMIC_STORE(&slot->NeedsUpdate, AL_TRUE);
  201. break;
  202. default:
  203. SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
  204. }
  205. done:
  206. ALCcontext_DecRef(context);
  207. }
  208. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
  209. {
  210. ALCcontext *context;
  211. switch(param)
  212. {
  213. case AL_EFFECTSLOT_GAIN:
  214. alAuxiliaryEffectSlotf(effectslot, param, values[0]);
  215. return;
  216. }
  217. context = GetContextRef();
  218. if(!context) return;
  219. if(LookupEffectSlot(context, effectslot) == NULL)
  220. SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
  221. switch(param)
  222. {
  223. default:
  224. SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
  225. }
  226. done:
  227. ALCcontext_DecRef(context);
  228. }
  229. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
  230. {
  231. ALCcontext *context;
  232. ALeffectslot *slot;
  233. context = GetContextRef();
  234. if(!context) return;
  235. if((slot=LookupEffectSlot(context, effectslot)) == NULL)
  236. SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
  237. switch(param)
  238. {
  239. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  240. *value = slot->AuxSendAuto;
  241. break;
  242. default:
  243. SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
  244. }
  245. done:
  246. ALCcontext_DecRef(context);
  247. }
  248. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
  249. {
  250. ALCcontext *context;
  251. switch(param)
  252. {
  253. case AL_EFFECTSLOT_EFFECT:
  254. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  255. alGetAuxiliaryEffectSloti(effectslot, param, values);
  256. return;
  257. }
  258. context = GetContextRef();
  259. if(!context) return;
  260. if(LookupEffectSlot(context, effectslot) == NULL)
  261. SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
  262. switch(param)
  263. {
  264. default:
  265. SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
  266. }
  267. done:
  268. ALCcontext_DecRef(context);
  269. }
  270. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
  271. {
  272. ALCcontext *context;
  273. ALeffectslot *slot;
  274. context = GetContextRef();
  275. if(!context) return;
  276. if((slot=LookupEffectSlot(context, effectslot)) == NULL)
  277. SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
  278. switch(param)
  279. {
  280. case AL_EFFECTSLOT_GAIN:
  281. *value = slot->Gain;
  282. break;
  283. default:
  284. SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
  285. }
  286. done:
  287. ALCcontext_DecRef(context);
  288. }
  289. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
  290. {
  291. ALCcontext *context;
  292. switch(param)
  293. {
  294. case AL_EFFECTSLOT_GAIN:
  295. alGetAuxiliaryEffectSlotf(effectslot, param, values);
  296. return;
  297. }
  298. context = GetContextRef();
  299. if(!context) return;
  300. if(LookupEffectSlot(context, effectslot) == NULL)
  301. SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
  302. switch(param)
  303. {
  304. default:
  305. SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
  306. }
  307. done:
  308. ALCcontext_DecRef(context);
  309. }
  310. static ALenum AddEffectSlotArray(ALCcontext *context, ALeffectslot **start, ALsizei count)
  311. {
  312. ALenum err = AL_NO_ERROR;
  313. LockContext(context);
  314. if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_ITER_END(context->ActiveAuxSlots), start, start+count))
  315. err = AL_OUT_OF_MEMORY;
  316. UnlockContext(context);
  317. return err;
  318. }
  319. static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot)
  320. {
  321. ALeffectslot **iter;
  322. LockContext(context);
  323. #define MATCH_SLOT(_i) (slot == *(_i))
  324. VECTOR_FIND_IF(iter, ALeffectslot*, context->ActiveAuxSlots, MATCH_SLOT);
  325. if(iter != VECTOR_ITER_END(context->ActiveAuxSlots))
  326. {
  327. *iter = VECTOR_BACK(context->ActiveAuxSlots);
  328. VECTOR_POP_BACK(context->ActiveAuxSlots);
  329. }
  330. #undef MATCH_SLOT
  331. UnlockContext(context);
  332. }
  333. void InitEffectFactoryMap(void)
  334. {
  335. InitUIntMap(&EffectStateFactoryMap, ~0);
  336. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_NULL, ALnullStateFactory_getFactory);
  337. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory);
  338. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_REVERB, ALreverbStateFactory_getFactory);
  339. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_AUTOWAH, ALautowahStateFactory_getFactory);
  340. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_CHORUS, ALchorusStateFactory_getFactory);
  341. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_COMPRESSOR, ALcompressorStateFactory_getFactory);
  342. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DISTORTION, ALdistortionStateFactory_getFactory);
  343. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_ECHO, ALechoStateFactory_getFactory);
  344. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EQUALIZER, ALequalizerStateFactory_getFactory);
  345. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_FLANGER, ALflangerStateFactory_getFactory);
  346. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_RING_MODULATOR, ALmodulatorStateFactory_getFactory);
  347. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_DIALOGUE, ALdedicatedStateFactory_getFactory);
  348. InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, ALdedicatedStateFactory_getFactory);
  349. }
  350. void DeinitEffectFactoryMap(void)
  351. {
  352. ResetUIntMap(&EffectStateFactoryMap);
  353. }
  354. ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
  355. {
  356. ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
  357. ALeffectStateFactory *factory;
  358. if(newtype != EffectSlot->EffectType)
  359. {
  360. ALeffectState *State;
  361. FPUCtl oldMode;
  362. factory = getFactoryByType(newtype);
  363. if(!factory)
  364. {
  365. ERR("Failed to find factory for effect type 0x%04x\n", newtype);
  366. return AL_INVALID_ENUM;
  367. }
  368. State = V0(factory,create)();
  369. if(!State)
  370. return AL_OUT_OF_MEMORY;
  371. SetMixerFPUMode(&oldMode);
  372. ALCdevice_Lock(Device);
  373. if(V(State,deviceUpdate)(Device) == AL_FALSE)
  374. {
  375. ALCdevice_Unlock(Device);
  376. RestoreFPUMode(&oldMode);
  377. DELETE_OBJ(State);
  378. return AL_OUT_OF_MEMORY;
  379. }
  380. State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
  381. if(!effect)
  382. {
  383. memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps));
  384. EffectSlot->EffectType = AL_EFFECT_NULL;
  385. }
  386. else
  387. {
  388. memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
  389. EffectSlot->EffectType = effect->type;
  390. }
  391. /* FIXME: This should be done asynchronously, but since the EffectState
  392. * object was changed, it needs an update before its Process method can
  393. * be called. */
  394. ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_FALSE);
  395. V(EffectSlot->EffectState,update)(Device, EffectSlot);
  396. ALCdevice_Unlock(Device);
  397. RestoreFPUMode(&oldMode);
  398. DELETE_OBJ(State);
  399. State = NULL;
  400. }
  401. else
  402. {
  403. if(effect)
  404. {
  405. ALCdevice_Lock(Device);
  406. memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
  407. ALCdevice_Unlock(Device);
  408. ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_TRUE);
  409. }
  410. }
  411. return AL_NO_ERROR;
  412. }
  413. ALenum InitEffectSlot(ALeffectslot *slot)
  414. {
  415. ALeffectStateFactory *factory;
  416. ALuint i, c;
  417. slot->EffectType = AL_EFFECT_NULL;
  418. factory = getFactoryByType(AL_EFFECT_NULL);
  419. if(!(slot->EffectState=V0(factory,create)()))
  420. return AL_OUT_OF_MEMORY;
  421. slot->Gain = 1.0;
  422. slot->AuxSendAuto = AL_TRUE;
  423. ATOMIC_INIT(&slot->NeedsUpdate, AL_FALSE);
  424. for(c = 0;c < 1;c++)
  425. {
  426. for(i = 0;i < BUFFERSIZE;i++)
  427. slot->WetBuffer[c][i] = 0.0f;
  428. }
  429. InitRef(&slot->ref, 0);
  430. return AL_NO_ERROR;
  431. }
  432. ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
  433. {
  434. ALsizei pos;
  435. for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
  436. {
  437. ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
  438. Context->EffectSlotMap.array[pos].value = NULL;
  439. DELETE_OBJ(temp->EffectState);
  440. FreeThunkEntry(temp->id);
  441. memset(temp, 0, sizeof(ALeffectslot));
  442. al_free(temp);
  443. }
  444. }