alAuxEffectSlot.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  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 "alError.h"
  28. #include "alListener.h"
  29. #include "alSource.h"
  30. #include "fpu_modes.h"
  31. #include "almalloc.h"
  32. extern inline void LockEffectSlotList(ALCcontext *context);
  33. extern inline void UnlockEffectSlotList(ALCcontext *context);
  34. static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context);
  35. static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context);
  36. static const struct {
  37. ALenum Type;
  38. EffectStateFactory* (*GetFactory)(void);
  39. } FactoryList[] = {
  40. { AL_EFFECT_NULL, NullStateFactory_getFactory },
  41. { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory },
  42. { AL_EFFECT_REVERB, ReverbStateFactory_getFactory },
  43. { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory },
  44. { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory },
  45. { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory },
  46. { AL_EFFECT_ECHO, EchoStateFactory_getFactory },
  47. { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory },
  48. { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory },
  49. { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory },
  50. { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory},
  51. { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory },
  52. { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory }
  53. };
  54. static inline EffectStateFactory *getFactoryByType(ALenum type)
  55. {
  56. size_t i;
  57. for(i = 0;i < COUNTOF(FactoryList);i++)
  58. {
  59. if(FactoryList[i].Type == type)
  60. return FactoryList[i].GetFactory();
  61. }
  62. return NULL;
  63. }
  64. static void ALeffectState_IncRef(ALeffectState *state);
  65. static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
  66. {
  67. id--;
  68. if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList)))
  69. return NULL;
  70. return VECTOR_ELEM(context->EffectSlotList, id);
  71. }
  72. static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
  73. {
  74. EffectSubList *sublist;
  75. ALuint lidx = (id-1) >> 6;
  76. ALsizei slidx = (id-1) & 0x3f;
  77. if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList)))
  78. return NULL;
  79. sublist = &VECTOR_ELEM(device->EffectList, lidx);
  80. if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
  81. return NULL;
  82. return sublist->Effects + slidx;
  83. }
  84. #define DO_UPDATEPROPS() do { \
  85. if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
  86. UpdateEffectSlotProps(slot, context); \
  87. else \
  88. ATOMIC_FLAG_CLEAR(&slot->PropsClean, almemory_order_release); \
  89. } while(0)
  90. AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
  91. {
  92. ALCdevice *device;
  93. ALCcontext *context;
  94. ALsizei cur;
  95. context = GetContextRef();
  96. if(!context) return;
  97. if(!(n >= 0))
  98. SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n);
  99. if(n == 0) goto done;
  100. LockEffectSlotList(context);
  101. device = context->Device;
  102. if(device->AuxiliaryEffectSlotMax - VECTOR_SIZE(context->EffectSlotList) < (ALuint)n)
  103. {
  104. UnlockEffectSlotList(context);
  105. SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Exceeding %u auxiliary effect slot limit",
  106. device->AuxiliaryEffectSlotMax);
  107. }
  108. for(cur = 0;cur < n;cur++)
  109. {
  110. ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList);
  111. ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList);
  112. ALeffectslot *slot = NULL;
  113. ALenum err = AL_OUT_OF_MEMORY;
  114. for(;iter != end;iter++)
  115. {
  116. if(!*iter)
  117. break;
  118. }
  119. if(iter == end)
  120. {
  121. VECTOR_PUSH_BACK(context->EffectSlotList, NULL);
  122. iter = &VECTOR_BACK(context->EffectSlotList);
  123. }
  124. slot = al_calloc(16, sizeof(ALeffectslot));
  125. if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
  126. {
  127. al_free(slot);
  128. UnlockEffectSlotList(context);
  129. alDeleteAuxiliaryEffectSlots(cur, effectslots);
  130. SETERR_GOTO(context, err, done, "Effect slot object allocation failed");
  131. }
  132. aluInitEffectPanning(slot);
  133. slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1;
  134. *iter = slot;
  135. effectslots[cur] = slot->id;
  136. }
  137. AddActiveEffectSlots(effectslots, n, context);
  138. UnlockEffectSlotList(context);
  139. done:
  140. ALCcontext_DecRef(context);
  141. }
  142. AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
  143. {
  144. ALCcontext *context;
  145. ALeffectslot *slot;
  146. ALsizei i;
  147. context = GetContextRef();
  148. if(!context) return;
  149. LockEffectSlotList(context);
  150. if(!(n >= 0))
  151. SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n);
  152. if(n == 0) goto done;
  153. for(i = 0;i < n;i++)
  154. {
  155. if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
  156. SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u",
  157. effectslots[i]);
  158. if(ReadRef(&slot->ref) != 0)
  159. SETERR_GOTO(context, AL_INVALID_NAME, done, "Deleting in-use effect slot %u",
  160. effectslots[i]);
  161. }
  162. // All effectslots are valid
  163. RemoveActiveEffectSlots(effectslots, n, context);
  164. for(i = 0;i < n;i++)
  165. {
  166. if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
  167. continue;
  168. VECTOR_ELEM(context->EffectSlotList, effectslots[i]-1) = NULL;
  169. DeinitEffectSlot(slot);
  170. memset(slot, 0, sizeof(*slot));
  171. al_free(slot);
  172. }
  173. done:
  174. UnlockEffectSlotList(context);
  175. ALCcontext_DecRef(context);
  176. }
  177. AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
  178. {
  179. ALCcontext *context;
  180. ALboolean ret;
  181. context = GetContextRef();
  182. if(!context) return AL_FALSE;
  183. LockEffectSlotList(context);
  184. ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
  185. UnlockEffectSlotList(context);
  186. ALCcontext_DecRef(context);
  187. return ret;
  188. }
  189. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
  190. {
  191. ALCdevice *device;
  192. ALCcontext *context;
  193. ALeffectslot *slot;
  194. ALeffect *effect = NULL;
  195. ALenum err;
  196. context = GetContextRef();
  197. if(!context) return;
  198. almtx_lock(&context->PropLock);
  199. LockEffectSlotList(context);
  200. if((slot=LookupEffectSlot(context, effectslot)) == NULL)
  201. SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
  202. switch(param)
  203. {
  204. case AL_EFFECTSLOT_EFFECT:
  205. device = context->Device;
  206. LockEffectList(device);
  207. effect = (value ? LookupEffect(device, value) : NULL);
  208. if(!(value == 0 || effect != NULL))
  209. {
  210. UnlockEffectList(device);
  211. SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid effect ID %u", value);
  212. }
  213. err = InitializeEffect(context, slot, effect);
  214. UnlockEffectList(device);
  215. if(err != AL_NO_ERROR)
  216. SETERR_GOTO(context, err, done, "Effect initialization failed");
  217. break;
  218. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  219. if(!(value == AL_TRUE || value == AL_FALSE))
  220. SETERR_GOTO(context, AL_INVALID_VALUE, done,
  221. "Effect slot auxiliary send auto out of range");
  222. slot->AuxSendAuto = value;
  223. break;
  224. default:
  225. SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot integer property 0x%04x",
  226. param);
  227. }
  228. DO_UPDATEPROPS();
  229. done:
  230. UnlockEffectSlotList(context);
  231. almtx_unlock(&context->PropLock);
  232. ALCcontext_DecRef(context);
  233. }
  234. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
  235. {
  236. ALCcontext *context;
  237. switch(param)
  238. {
  239. case AL_EFFECTSLOT_EFFECT:
  240. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  241. alAuxiliaryEffectSloti(effectslot, param, values[0]);
  242. return;
  243. }
  244. context = GetContextRef();
  245. if(!context) return;
  246. LockEffectSlotList(context);
  247. if(LookupEffectSlot(context, effectslot) == NULL)
  248. SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
  249. switch(param)
  250. {
  251. default:
  252. alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
  253. param);
  254. }
  255. done:
  256. UnlockEffectSlotList(context);
  257. ALCcontext_DecRef(context);
  258. }
  259. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
  260. {
  261. ALCcontext *context;
  262. ALeffectslot *slot;
  263. context = GetContextRef();
  264. if(!context) return;
  265. almtx_lock(&context->PropLock);
  266. LockEffectSlotList(context);
  267. if((slot=LookupEffectSlot(context, effectslot)) == NULL)
  268. SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
  269. switch(param)
  270. {
  271. case AL_EFFECTSLOT_GAIN:
  272. if(!(value >= 0.0f && value <= 1.0f))
  273. SETERR_GOTO(context, AL_INVALID_VALUE, done, "Effect slot gain out of range");
  274. slot->Gain = value;
  275. break;
  276. default:
  277. SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot float property 0x%04x",
  278. param);
  279. }
  280. DO_UPDATEPROPS();
  281. done:
  282. UnlockEffectSlotList(context);
  283. almtx_unlock(&context->PropLock);
  284. ALCcontext_DecRef(context);
  285. }
  286. AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
  287. {
  288. ALCcontext *context;
  289. switch(param)
  290. {
  291. case AL_EFFECTSLOT_GAIN:
  292. alAuxiliaryEffectSlotf(effectslot, param, values[0]);
  293. return;
  294. }
  295. context = GetContextRef();
  296. if(!context) return;
  297. LockEffectSlotList(context);
  298. if(LookupEffectSlot(context, effectslot) == NULL)
  299. SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
  300. switch(param)
  301. {
  302. default:
  303. alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
  304. param);
  305. }
  306. done:
  307. UnlockEffectSlotList(context);
  308. ALCcontext_DecRef(context);
  309. }
  310. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
  311. {
  312. ALCcontext *context;
  313. ALeffectslot *slot;
  314. context = GetContextRef();
  315. if(!context) return;
  316. LockEffectSlotList(context);
  317. if((slot=LookupEffectSlot(context, effectslot)) == NULL)
  318. SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
  319. switch(param)
  320. {
  321. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  322. *value = slot->AuxSendAuto;
  323. break;
  324. default:
  325. alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param);
  326. }
  327. done:
  328. UnlockEffectSlotList(context);
  329. ALCcontext_DecRef(context);
  330. }
  331. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
  332. {
  333. ALCcontext *context;
  334. switch(param)
  335. {
  336. case AL_EFFECTSLOT_EFFECT:
  337. case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
  338. alGetAuxiliaryEffectSloti(effectslot, param, values);
  339. return;
  340. }
  341. context = GetContextRef();
  342. if(!context) return;
  343. LockEffectSlotList(context);
  344. if(LookupEffectSlot(context, effectslot) == NULL)
  345. SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
  346. switch(param)
  347. {
  348. default:
  349. alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
  350. param);
  351. }
  352. done:
  353. UnlockEffectSlotList(context);
  354. ALCcontext_DecRef(context);
  355. }
  356. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
  357. {
  358. ALCcontext *context;
  359. ALeffectslot *slot;
  360. context = GetContextRef();
  361. if(!context) return;
  362. LockEffectSlotList(context);
  363. if((slot=LookupEffectSlot(context, effectslot)) == NULL)
  364. SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
  365. switch(param)
  366. {
  367. case AL_EFFECTSLOT_GAIN:
  368. *value = slot->Gain;
  369. break;
  370. default:
  371. alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param);
  372. }
  373. done:
  374. UnlockEffectSlotList(context);
  375. ALCcontext_DecRef(context);
  376. }
  377. AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
  378. {
  379. ALCcontext *context;
  380. switch(param)
  381. {
  382. case AL_EFFECTSLOT_GAIN:
  383. alGetAuxiliaryEffectSlotf(effectslot, param, values);
  384. return;
  385. }
  386. context = GetContextRef();
  387. if(!context) return;
  388. LockEffectSlotList(context);
  389. if(LookupEffectSlot(context, effectslot) == NULL)
  390. SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
  391. switch(param)
  392. {
  393. default:
  394. alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
  395. param);
  396. }
  397. done:
  398. UnlockEffectSlotList(context);
  399. ALCcontext_DecRef(context);
  400. }
  401. ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
  402. {
  403. ALCdevice *Device = Context->Device;
  404. ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
  405. struct ALeffectslotProps *props;
  406. ALeffectState *State;
  407. if(newtype != EffectSlot->Effect.Type)
  408. {
  409. EffectStateFactory *factory;
  410. factory = getFactoryByType(newtype);
  411. if(!factory)
  412. {
  413. ERR("Failed to find factory for effect type 0x%04x\n", newtype);
  414. return AL_INVALID_ENUM;
  415. }
  416. State = EffectStateFactory_create(factory);
  417. if(!State) return AL_OUT_OF_MEMORY;
  418. START_MIXER_MODE();
  419. almtx_lock(&Device->BackendLock);
  420. State->OutBuffer = Device->Dry.Buffer;
  421. State->OutChannels = Device->Dry.NumChannels;
  422. if(V(State,deviceUpdate)(Device) == AL_FALSE)
  423. {
  424. almtx_unlock(&Device->BackendLock);
  425. LEAVE_MIXER_MODE();
  426. ALeffectState_DecRef(State);
  427. return AL_OUT_OF_MEMORY;
  428. }
  429. almtx_unlock(&Device->BackendLock);
  430. END_MIXER_MODE();
  431. if(!effect)
  432. {
  433. EffectSlot->Effect.Type = AL_EFFECT_NULL;
  434. memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props));
  435. }
  436. else
  437. {
  438. EffectSlot->Effect.Type = effect->type;
  439. EffectSlot->Effect.Props = effect->Props;
  440. }
  441. ALeffectState_DecRef(EffectSlot->Effect.State);
  442. EffectSlot->Effect.State = State;
  443. }
  444. else if(effect)
  445. EffectSlot->Effect.Props = effect->Props;
  446. /* Remove state references from old effect slot property updates. */
  447. props = ATOMIC_LOAD_SEQ(&Context->FreeEffectslotProps);
  448. while(props)
  449. {
  450. if(props->State)
  451. ALeffectState_DecRef(props->State);
  452. props->State = NULL;
  453. props = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
  454. }
  455. return AL_NO_ERROR;
  456. }
  457. static void ALeffectState_IncRef(ALeffectState *state)
  458. {
  459. uint ref;
  460. ref = IncrementRef(&state->Ref);
  461. TRACEREF("%p increasing refcount to %u\n", state, ref);
  462. }
  463. void ALeffectState_DecRef(ALeffectState *state)
  464. {
  465. uint ref;
  466. ref = DecrementRef(&state->Ref);
  467. TRACEREF("%p decreasing refcount to %u\n", state, ref);
  468. if(ref == 0) DELETE_OBJ(state);
  469. }
  470. void ALeffectState_Construct(ALeffectState *state)
  471. {
  472. InitRef(&state->Ref, 1);
  473. state->OutBuffer = NULL;
  474. state->OutChannels = 0;
  475. }
  476. void ALeffectState_Destruct(ALeffectState *UNUSED(state))
  477. {
  478. }
  479. static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context)
  480. {
  481. struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots,
  482. almemory_order_acquire);
  483. struct ALeffectslotArray *newarray = NULL;
  484. ALsizei newcount = curarray->count + count;
  485. ALCdevice *device = context->Device;
  486. ALsizei i, j;
  487. /* Insert the new effect slots into the head of the array, followed by the
  488. * existing ones.
  489. */
  490. newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount));
  491. newarray->count = newcount;
  492. for(i = 0;i < count;i++)
  493. newarray->slot[i] = LookupEffectSlot(context, slotids[i]);
  494. for(j = 0;i < newcount;)
  495. newarray->slot[i++] = curarray->slot[j++];
  496. /* Remove any duplicates (first instance of each will be kept). */
  497. for(i = 1;i < newcount;i++)
  498. {
  499. for(j = i;j != 0;)
  500. {
  501. if(UNLIKELY(newarray->slot[i] == newarray->slot[--j]))
  502. {
  503. newcount--;
  504. for(j = i;j < newcount;j++)
  505. newarray->slot[j] = newarray->slot[j+1];
  506. i--;
  507. break;
  508. }
  509. }
  510. }
  511. /* Reallocate newarray if the new size ended up smaller from duplicate
  512. * removal.
  513. */
  514. if(UNLIKELY(newcount < newarray->count))
  515. {
  516. struct ALeffectslotArray *tmpnewarray = al_calloc(DEF_ALIGN,
  517. FAM_SIZE(struct ALeffectslotArray, slot, newcount));
  518. memcpy(tmpnewarray, newarray, FAM_SIZE(struct ALeffectslotArray, slot, newcount));
  519. al_free(newarray);
  520. newarray = tmpnewarray;
  521. newarray->count = newcount;
  522. }
  523. curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel);
  524. while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
  525. althrd_yield();
  526. al_free(curarray);
  527. }
  528. static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context)
  529. {
  530. struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots,
  531. almemory_order_acquire);
  532. struct ALeffectslotArray *newarray = NULL;
  533. ALCdevice *device = context->Device;
  534. ALsizei i, j;
  535. /* Don't shrink the allocated array size since we don't know how many (if
  536. * any) of the effect slots to remove are in the array.
  537. */
  538. newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, curarray->count));
  539. newarray->count = 0;
  540. for(i = 0;i < curarray->count;i++)
  541. {
  542. /* Insert this slot into the new array only if it's not one to remove. */
  543. ALeffectslot *slot = curarray->slot[i];
  544. for(j = count;j != 0;)
  545. {
  546. if(slot->id == slotids[--j])
  547. goto skip_ins;
  548. }
  549. newarray->slot[newarray->count++] = slot;
  550. skip_ins: ;
  551. }
  552. /* TODO: Could reallocate newarray now that we know it's needed size. */
  553. curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel);
  554. while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
  555. althrd_yield();
  556. al_free(curarray);
  557. }
  558. ALenum InitEffectSlot(ALeffectslot *slot)
  559. {
  560. EffectStateFactory *factory;
  561. slot->Effect.Type = AL_EFFECT_NULL;
  562. factory = getFactoryByType(AL_EFFECT_NULL);
  563. slot->Effect.State = EffectStateFactory_create(factory);
  564. if(!slot->Effect.State) return AL_OUT_OF_MEMORY;
  565. slot->Gain = 1.0;
  566. slot->AuxSendAuto = AL_TRUE;
  567. ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_relaxed);
  568. InitRef(&slot->ref, 0);
  569. ATOMIC_INIT(&slot->Update, NULL);
  570. slot->Params.Gain = 1.0f;
  571. slot->Params.AuxSendAuto = AL_TRUE;
  572. ALeffectState_IncRef(slot->Effect.State);
  573. slot->Params.EffectState = slot->Effect.State;
  574. slot->Params.RoomRolloff = 0.0f;
  575. slot->Params.DecayTime = 0.0f;
  576. slot->Params.DecayLFRatio = 0.0f;
  577. slot->Params.DecayHFRatio = 0.0f;
  578. slot->Params.DecayHFLimit = AL_FALSE;
  579. slot->Params.AirAbsorptionGainHF = 1.0f;
  580. return AL_NO_ERROR;
  581. }
  582. void DeinitEffectSlot(ALeffectslot *slot)
  583. {
  584. struct ALeffectslotProps *props;
  585. props = ATOMIC_LOAD_SEQ(&slot->Update);
  586. if(props)
  587. {
  588. if(props->State) ALeffectState_DecRef(props->State);
  589. TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
  590. al_free(props);
  591. }
  592. ALeffectState_DecRef(slot->Effect.State);
  593. if(slot->Params.EffectState)
  594. ALeffectState_DecRef(slot->Params.EffectState);
  595. }
  596. void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
  597. {
  598. struct ALeffectslotProps *props;
  599. ALeffectState *oldstate;
  600. /* Get an unused property container, or allocate a new one as needed. */
  601. props = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed);
  602. if(!props)
  603. props = al_calloc(16, sizeof(*props));
  604. else
  605. {
  606. struct ALeffectslotProps *next;
  607. do {
  608. next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
  609. } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeEffectslotProps, &props, next,
  610. almemory_order_seq_cst, almemory_order_acquire) == 0);
  611. }
  612. /* Copy in current property values. */
  613. props->Gain = slot->Gain;
  614. props->AuxSendAuto = slot->AuxSendAuto;
  615. props->Type = slot->Effect.Type;
  616. props->Props = slot->Effect.Props;
  617. /* Swap out any stale effect state object there may be in the container, to
  618. * delete it.
  619. */
  620. ALeffectState_IncRef(slot->Effect.State);
  621. oldstate = props->State;
  622. props->State = slot->Effect.State;
  623. /* Set the new container for updating internal parameters. */
  624. props = ATOMIC_EXCHANGE_PTR(&slot->Update, props, almemory_order_acq_rel);
  625. if(props)
  626. {
  627. /* If there was an unused update container, put it back in the
  628. * freelist.
  629. */
  630. ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props);
  631. }
  632. if(oldstate)
  633. ALeffectState_DecRef(oldstate);
  634. }
  635. void UpdateAllEffectSlotProps(ALCcontext *context)
  636. {
  637. struct ALeffectslotArray *auxslots;
  638. ALsizei i;
  639. LockEffectSlotList(context);
  640. auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire);
  641. for(i = 0;i < auxslots->count;i++)
  642. {
  643. ALeffectslot *slot = auxslots->slot[i];
  644. if(!ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel))
  645. UpdateEffectSlotProps(slot, context);
  646. }
  647. UnlockEffectSlotList(context);
  648. }
  649. ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context)
  650. {
  651. ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList);
  652. ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList);
  653. size_t leftover = 0;
  654. for(;iter != end;iter++)
  655. {
  656. ALeffectslot *slot = *iter;
  657. if(!slot) continue;
  658. *iter = NULL;
  659. DeinitEffectSlot(slot);
  660. memset(slot, 0, sizeof(*slot));
  661. al_free(slot);
  662. ++leftover;
  663. }
  664. if(leftover > 0)
  665. WARN("(%p) Deleted "SZFMT" AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s");
  666. }