2007-12-18 01:43:19 +00:00
|
|
|
/**
|
|
|
|
* OpenAL cross platform audio library
|
|
|
|
* Copyright (C) 1999-2007 by authors.
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
2014-08-18 12:11:03 +00:00
|
|
|
* Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2007-12-18 01:43:19 +00:00
|
|
|
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2008-01-16 22:09:04 +00:00
|
|
|
#include <stdlib.h>
|
Implement AL_EFFECT_REVERB
Here is a quick description of how the reverb effect works:
+--->---+*(4)
| V new sample
+-----+---+---+ |
|extra|ltr|ref| <- +*(1)
+-----+---+---+
(3,5)*| |*(2)
+-->|
V
out sample
1) Apply master reverb gain to incoming sample and place it at the head of the
buffer. The master reverb gainhf was already applied when the source was
initially mixed.
2) Copy the delayed reflection sample to an output sample and apply the
reflection gain.
3) Apply the late reverb gain to the late reverb sample
4) Copy the end of the buffer, applying a decay gain and the decay hf ratio,
and add to the late reverb.
5) Copy the late reverb sample, adding to the output sample.
Then the head and sampling points are shifted forward, and done again for each
new sample. The extra buffer length is determined by the Reverb Density
property. A value of 0 gives a length of 0.1 seconds (long, with fairly
distinct echos) , and 1 gives 0.075 seconds (short, indistinct echos).
The decay gain is calculated such that after a number of loops to satisfy the
Decay Time, a sample will be 1/32768th as powerful (virtually insignificant to
the resulting output, and only getting further reduced). It is calculated as:
DecayGain = pow(1.0f/32768.0f, 1.0/(DecayTime/ExtraLength));
Things to note: Reverb Diffusion is not currently handled, nor is Decay HF
Limit. Decay HF Ratios above 1 probably give incorrect results. Also, this
method likely sucks, but it's the best I can come up with before release. :)
2008-01-19 05:25:40 +00:00
|
|
|
#include <math.h>
|
2008-01-16 22:09:04 +00:00
|
|
|
|
2007-12-18 01:43:19 +00:00
|
|
|
#include "AL/al.h"
|
|
|
|
#include "AL/alc.h"
|
|
|
|
#include "alMain.h"
|
|
|
|
#include "alAuxEffectSlot.h"
|
2008-01-01 03:34:52 +00:00
|
|
|
#include "alThunk.h"
|
|
|
|
#include "alError.h"
|
2016-05-12 01:40:17 +00:00
|
|
|
#include "alListener.h"
|
2009-11-26 00:21:47 +00:00
|
|
|
#include "alSource.h"
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2016-03-29 07:44:58 +00:00
|
|
|
#include "almalloc.h"
|
|
|
|
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-11-04 21:44:46 +00:00
|
|
|
extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id);
|
|
|
|
extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id);
|
|
|
|
|
2014-07-06 10:27:39 +00:00
|
|
|
static ALenum AddEffectSlotArray(ALCcontext *Context, ALeffectslot **start, ALsizei count);
|
2014-04-11 03:49:01 +00:00
|
|
|
static void RemoveEffectSlotArray(ALCcontext *Context, const ALeffectslot *slot);
|
Implement AL_EFFECT_REVERB
Here is a quick description of how the reverb effect works:
+--->---+*(4)
| V new sample
+-----+---+---+ |
|extra|ltr|ref| <- +*(1)
+-----+---+---+
(3,5)*| |*(2)
+-->|
V
out sample
1) Apply master reverb gain to incoming sample and place it at the head of the
buffer. The master reverb gainhf was already applied when the source was
initially mixed.
2) Copy the delayed reflection sample to an output sample and apply the
reflection gain.
3) Apply the late reverb gain to the late reverb sample
4) Copy the end of the buffer, applying a decay gain and the decay hf ratio,
and add to the late reverb.
5) Copy the late reverb sample, adding to the output sample.
Then the head and sampling points are shifted forward, and done again for each
new sample. The extra buffer length is determined by the Reverb Density
property. A value of 0 gives a length of 0.1 seconds (long, with fairly
distinct echos) , and 1 gives 0.075 seconds (short, indistinct echos).
The decay gain is calculated such that after a number of loops to satisfy the
Decay Time, a sample will be 1/32768th as powerful (virtually insignificant to
the resulting output, and only getting further reduced). It is calculated as:
DecayGain = pow(1.0f/32768.0f, 1.0/(DecayTime/ExtraLength));
Things to note: Reverb Diffusion is not currently handled, nor is Decay HF
Limit. Decay HF Ratios above 1 probably give incorrect results. Also, this
method likely sucks, but it's the best I can come up with before release. :)
2008-01-19 05:25:40 +00:00
|
|
|
|
2013-05-21 19:47:18 +00:00
|
|
|
|
|
|
|
static UIntMap EffectStateFactoryMap;
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALeffectStateFactory *getFactoryByType(ALenum type)
|
2013-05-21 19:47:18 +00:00
|
|
|
{
|
2013-05-27 20:41:16 +00:00
|
|
|
ALeffectStateFactory* (*getFactory)(void) = LookupUIntMapKey(&EffectStateFactoryMap, type);
|
|
|
|
if(getFactory != NULL)
|
|
|
|
return getFactory();
|
|
|
|
return NULL;
|
2013-05-21 19:47:18 +00:00
|
|
|
}
|
2013-03-19 12:39:34 +00:00
|
|
|
|
2010-05-12 09:20:14 +00:00
|
|
|
|
2010-03-24 00:44:01 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext *context;
|
2014-07-06 10:27:39 +00:00
|
|
|
VECTOR(ALeffectslot*) slotvec;
|
2013-10-07 18:30:11 +00:00
|
|
|
ALsizei cur;
|
|
|
|
ALenum err;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2014-04-11 03:49:01 +00:00
|
|
|
VECTOR_INIT(slotvec);
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
if(!(n >= 0))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
2014-04-11 03:49:01 +00:00
|
|
|
if(!VECTOR_RESERVE(slotvec, n))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
for(cur = 0;cur < n;cur++)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
|
|
|
|
err = AL_OUT_OF_MEMORY;
|
|
|
|
if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
al_free(slot);
|
|
|
|
alDeleteAuxiliaryEffectSlots(cur, effectslots);
|
|
|
|
SET_ERROR_AND_GOTO(context, err, done);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
2013-10-07 18:30:11 +00:00
|
|
|
|
|
|
|
err = NewThunkEntry(&slot->id);
|
|
|
|
if(err == AL_NO_ERROR)
|
|
|
|
err = InsertUIntMapEntry(&context->EffectSlotMap, slot->id, slot);
|
2012-04-25 05:57:23 +00:00
|
|
|
if(err != AL_NO_ERROR)
|
2013-03-24 20:55:41 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
FreeThunkEntry(slot->id);
|
2016-05-13 01:26:33 +00:00
|
|
|
DELETE_OBJ(slot->Params.EffectState);
|
2013-10-07 18:30:11 +00:00
|
|
|
al_free(slot);
|
|
|
|
|
2012-04-25 05:57:23 +00:00
|
|
|
alDeleteAuxiliaryEffectSlots(cur, effectslots);
|
2013-10-07 18:30:11 +00:00
|
|
|
SET_ERROR_AND_GOTO(context, err, done);
|
2013-03-24 20:55:41 +00:00
|
|
|
}
|
2013-10-07 18:30:11 +00:00
|
|
|
|
2016-01-28 08:02:46 +00:00
|
|
|
aluInitEffectPanning(slot);
|
|
|
|
|
2014-04-11 03:49:01 +00:00
|
|
|
VECTOR_PUSH_BACK(slotvec, slot);
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
effectslots[cur] = slot->id;
|
|
|
|
}
|
2016-04-15 19:22:54 +00:00
|
|
|
err = AddEffectSlotArray(context, VECTOR_BEGIN(slotvec), n);
|
2013-10-07 18:30:11 +00:00
|
|
|
if(err != AL_NO_ERROR)
|
|
|
|
{
|
|
|
|
alDeleteAuxiliaryEffectSlots(cur, effectslots);
|
|
|
|
SET_ERROR_AND_GOTO(context, err, done);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
done:
|
2014-04-11 03:49:01 +00:00
|
|
|
VECTOR_DEINIT(slotvec);
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2011-09-22 07:31:42 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext *context;
|
2012-04-25 05:57:23 +00:00
|
|
|
ALeffectslot *slot;
|
2007-12-18 01:43:19 +00:00
|
|
|
ALsizei i;
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
if(!(n >= 0))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
for(i = 0;i < n;i++)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
2014-05-14 09:47:07 +00:00
|
|
|
if(ReadRef(&slot->ref) != 0)
|
2013-10-07 18:30:11 +00:00
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
|
|
|
|
}
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
// All effectslots are valid
|
|
|
|
for(i = 0;i < n;i++)
|
|
|
|
{
|
|
|
|
if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
|
|
|
|
continue;
|
|
|
|
FreeThunkEntry(slot->id);
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
RemoveEffectSlotArray(context, slot);
|
2016-05-13 01:26:33 +00:00
|
|
|
DeinitEffectSlot(slot);
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
memset(slot, 0, sizeof(*slot));
|
|
|
|
al_free(slot);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
done:
|
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2010-03-24 00:44:01 +00:00
|
|
|
AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext *context;
|
|
|
|
ALboolean ret;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return AL_FALSE;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
return ret;
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2012-04-20 05:40:40 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALeffectslot *slot;
|
2012-04-25 05:57:23 +00:00
|
|
|
ALeffect *effect = NULL;
|
|
|
|
ALenum err;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2016-05-13 01:26:33 +00:00
|
|
|
WriteLock(&context->PropLock);
|
2013-10-07 18:30:11 +00:00
|
|
|
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
switch(param)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
case AL_EFFECTSLOT_EFFECT:
|
2016-05-13 01:26:33 +00:00
|
|
|
device = context->Device;
|
2016-05-13 06:12:11 +00:00
|
|
|
|
|
|
|
LockEffectsRead(device);
|
2013-10-07 18:30:11 +00:00
|
|
|
effect = (value ? LookupEffect(device, value) : NULL);
|
|
|
|
if(!(value == 0 || effect != NULL))
|
2016-05-13 06:12:11 +00:00
|
|
|
{
|
|
|
|
UnlockEffectsRead(device);
|
2013-10-07 18:30:11 +00:00
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
2016-05-13 06:12:11 +00:00
|
|
|
}
|
2013-10-07 18:30:11 +00:00
|
|
|
err = InitializeEffect(device, slot, effect);
|
2016-05-13 06:12:11 +00:00
|
|
|
UnlockEffectsRead(device);
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
if(err != AL_NO_ERROR)
|
|
|
|
SET_ERROR_AND_GOTO(context, err, done);
|
|
|
|
break;
|
2007-12-18 22:22:59 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
|
|
|
|
if(!(value == AL_TRUE || value == AL_FALSE))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
slot->AuxSendAuto = value;
|
2016-05-15 08:19:05 +00:00
|
|
|
UpdateEffectSlotProps(slot);
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-15 06:43:40 +00:00
|
|
|
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
|
|
|
|
UpdateAllSourceProps(context);
|
2013-10-07 18:30:11 +00:00
|
|
|
break;
|
2007-12-19 01:41:44 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
default:
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
done:
|
2016-05-13 01:26:33 +00:00
|
|
|
WriteUnlock(&context->PropLock);
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2012-04-20 05:40:40 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext *context;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2011-06-16 16:14:41 +00:00
|
|
|
switch(param)
|
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
case AL_EFFECTSLOT_EFFECT:
|
|
|
|
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
|
|
|
|
alAuxiliaryEffectSloti(effectslot, param, values[0]);
|
|
|
|
return;
|
2011-06-16 16:14:41 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
if(LookupEffectSlot(context, effectslot) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
switch(param)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
default:
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
done:
|
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2012-04-20 05:40:40 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext *context;
|
|
|
|
ALeffectslot *slot;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2016-05-13 01:26:33 +00:00
|
|
|
WriteLock(&context->PropLock);
|
2013-10-07 18:30:11 +00:00
|
|
|
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
switch(param)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
case AL_EFFECTSLOT_GAIN:
|
|
|
|
if(!(value >= 0.0f && value <= 1.0f))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
slot->Gain = value;
|
|
|
|
break;
|
2007-12-18 23:47:24 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
default:
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
2016-05-15 08:19:05 +00:00
|
|
|
UpdateEffectSlotProps(slot);
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
done:
|
2016-05-13 01:26:33 +00:00
|
|
|
WriteUnlock(&context->PropLock);
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2012-04-20 05:40:40 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext *context;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2011-06-16 16:14:41 +00:00
|
|
|
switch(param)
|
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
case AL_EFFECTSLOT_GAIN:
|
|
|
|
alAuxiliaryEffectSlotf(effectslot, param, values[0]);
|
|
|
|
return;
|
2011-06-16 16:14:41 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
if(LookupEffectSlot(context, effectslot) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
switch(param)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
default:
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
done:
|
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2012-04-20 05:40:40 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext *context;
|
|
|
|
ALeffectslot *slot;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
switch(param)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
|
|
|
|
*value = slot->AuxSendAuto;
|
|
|
|
break;
|
2007-12-19 01:41:44 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
default:
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
done:
|
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2012-04-20 05:40:40 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext *context;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2011-06-16 16:14:41 +00:00
|
|
|
switch(param)
|
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
case AL_EFFECTSLOT_EFFECT:
|
|
|
|
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
|
|
|
|
alGetAuxiliaryEffectSloti(effectslot, param, values);
|
|
|
|
return;
|
2011-06-16 16:14:41 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
if(LookupEffectSlot(context, effectslot) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
switch(param)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
default:
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
done:
|
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2012-04-20 05:40:40 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext *context;
|
|
|
|
ALeffectslot *slot;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
switch(param)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
case AL_EFFECTSLOT_GAIN:
|
|
|
|
*value = slot->Gain;
|
|
|
|
break;
|
2007-12-18 23:47:24 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
default:
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
done:
|
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2012-04-20 05:40:40 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
ALCcontext *context;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2011-06-16 16:14:41 +00:00
|
|
|
switch(param)
|
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
case AL_EFFECTSLOT_GAIN:
|
|
|
|
alGetAuxiliaryEffectSlotf(effectslot, param, values);
|
|
|
|
return;
|
2011-06-16 16:14:41 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
if(LookupEffectSlot(context, effectslot) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
switch(param)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2013-10-07 18:30:11 +00:00
|
|
|
default:
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
done:
|
|
|
|
ALCcontext_DecRef(context);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-06 10:27:39 +00:00
|
|
|
static ALenum AddEffectSlotArray(ALCcontext *context, ALeffectslot **start, ALsizei count)
|
2014-04-11 03:49:01 +00:00
|
|
|
{
|
|
|
|
ALenum err = AL_NO_ERROR;
|
|
|
|
|
|
|
|
LockContext(context);
|
2016-04-15 19:22:54 +00:00
|
|
|
if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_END(context->ActiveAuxSlots), start, start+count))
|
2014-04-11 03:49:01 +00:00
|
|
|
err = AL_OUT_OF_MEMORY;
|
|
|
|
UnlockContext(context);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot)
|
2011-08-31 03:13:42 +00:00
|
|
|
{
|
2014-07-06 12:16:44 +00:00
|
|
|
ALeffectslot **iter;
|
2011-08-31 03:13:42 +00:00
|
|
|
|
2013-10-07 18:30:11 +00:00
|
|
|
LockContext(context);
|
2014-07-06 12:16:44 +00:00
|
|
|
#define MATCH_SLOT(_i) (slot == *(_i))
|
|
|
|
VECTOR_FIND_IF(iter, ALeffectslot*, context->ActiveAuxSlots, MATCH_SLOT);
|
2016-04-15 19:22:54 +00:00
|
|
|
if(iter != VECTOR_END(context->ActiveAuxSlots))
|
2011-08-31 03:13:42 +00:00
|
|
|
{
|
2014-07-06 12:16:44 +00:00
|
|
|
*iter = VECTOR_BACK(context->ActiveAuxSlots);
|
|
|
|
VECTOR_POP_BACK(context->ActiveAuxSlots);
|
2011-08-31 03:13:42 +00:00
|
|
|
}
|
2014-07-06 12:16:44 +00:00
|
|
|
#undef MATCH_SLOT
|
2013-10-07 18:30:11 +00:00
|
|
|
UnlockContext(context);
|
2011-08-31 03:13:42 +00:00
|
|
|
}
|
|
|
|
|
2011-09-02 01:51:24 +00:00
|
|
|
|
2013-05-21 19:47:18 +00:00
|
|
|
void InitEffectFactoryMap(void)
|
2013-03-19 12:39:34 +00:00
|
|
|
{
|
2013-05-21 19:47:18 +00:00
|
|
|
InitUIntMap(&EffectStateFactoryMap, ~0);
|
|
|
|
|
2013-05-27 20:41:16 +00:00
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_NULL, ALnullStateFactory_getFactory);
|
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory);
|
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_REVERB, ALreverbStateFactory_getFactory);
|
2013-10-03 10:32:54 +00:00
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_AUTOWAH, ALautowahStateFactory_getFactory);
|
2013-05-27 20:41:16 +00:00
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_CHORUS, ALchorusStateFactory_getFactory);
|
2013-10-03 14:55:12 +00:00
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_COMPRESSOR, ALcompressorStateFactory_getFactory);
|
2013-05-27 20:41:16 +00:00
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DISTORTION, ALdistortionStateFactory_getFactory);
|
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_ECHO, ALechoStateFactory_getFactory);
|
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EQUALIZER, ALequalizerStateFactory_getFactory);
|
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_FLANGER, ALflangerStateFactory_getFactory);
|
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_RING_MODULATOR, ALmodulatorStateFactory_getFactory);
|
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_DIALOGUE, ALdedicatedStateFactory_getFactory);
|
|
|
|
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, ALdedicatedStateFactory_getFactory);
|
2013-05-21 19:47:18 +00:00
|
|
|
}
|
2011-09-02 01:51:24 +00:00
|
|
|
|
2013-05-21 19:47:18 +00:00
|
|
|
void DeinitEffectFactoryMap(void)
|
|
|
|
{
|
|
|
|
ResetUIntMap(&EffectStateFactoryMap);
|
2013-03-19 12:39:34 +00:00
|
|
|
}
|
|
|
|
|
2013-05-21 19:47:18 +00:00
|
|
|
|
2013-03-19 12:39:34 +00:00
|
|
|
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
|
|
|
|
{
|
|
|
|
ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
|
2013-05-21 19:47:18 +00:00
|
|
|
ALeffectStateFactory *factory;
|
2011-09-02 01:51:24 +00:00
|
|
|
|
2016-05-13 01:26:33 +00:00
|
|
|
if(newtype != EffectSlot->Effect.Type)
|
2011-09-02 01:51:24 +00:00
|
|
|
{
|
2013-03-19 12:39:34 +00:00
|
|
|
ALeffectState *State;
|
2012-09-16 08:35:16 +00:00
|
|
|
FPUCtl oldMode;
|
2013-03-19 12:39:34 +00:00
|
|
|
|
2013-05-21 19:47:18 +00:00
|
|
|
factory = getFactoryByType(newtype);
|
|
|
|
if(!factory)
|
|
|
|
{
|
|
|
|
ERR("Failed to find factory for effect type 0x%04x\n", newtype);
|
|
|
|
return AL_INVALID_ENUM;
|
|
|
|
}
|
2013-11-03 00:30:28 +00:00
|
|
|
State = V0(factory,create)();
|
2016-05-28 02:40:54 +00:00
|
|
|
if(!State) return AL_OUT_OF_MEMORY;
|
2013-03-19 12:39:34 +00:00
|
|
|
|
2012-09-16 08:35:16 +00:00
|
|
|
SetMixerFPUMode(&oldMode);
|
2016-05-28 02:40:54 +00:00
|
|
|
almtx_lock(&Device->BackendLock);
|
2016-03-17 17:10:26 +00:00
|
|
|
State->OutBuffer = Device->Dry.Buffer;
|
|
|
|
State->OutChannels = Device->Dry.NumChannels;
|
2013-11-03 00:30:28 +00:00
|
|
|
if(V(State,deviceUpdate)(Device) == AL_FALSE)
|
2009-05-31 18:54:49 +00:00
|
|
|
{
|
2016-05-28 02:40:54 +00:00
|
|
|
almtx_unlock(&Device->BackendLock);
|
2013-03-19 12:39:34 +00:00
|
|
|
RestoreFPUMode(&oldMode);
|
2013-05-22 06:42:40 +00:00
|
|
|
DELETE_OBJ(State);
|
2012-03-13 21:58:34 +00:00
|
|
|
return AL_OUT_OF_MEMORY;
|
2009-05-31 18:54:49 +00:00
|
|
|
}
|
2016-05-28 02:40:54 +00:00
|
|
|
almtx_unlock(&Device->BackendLock);
|
2012-09-16 08:35:16 +00:00
|
|
|
RestoreFPUMode(&oldMode);
|
2011-09-29 12:25:01 +00:00
|
|
|
|
2016-05-13 02:05:06 +00:00
|
|
|
if(!effect)
|
|
|
|
{
|
|
|
|
EffectSlot->Effect.Type = AL_EFFECT_NULL;
|
|
|
|
memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
EffectSlot->Effect.Type = effect->type;
|
|
|
|
memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props));
|
|
|
|
}
|
2016-05-13 01:26:33 +00:00
|
|
|
|
2016-05-13 02:05:06 +00:00
|
|
|
EffectSlot->Effect.State = State;
|
2016-05-15 08:19:05 +00:00
|
|
|
UpdateEffectSlotProps(EffectSlot);
|
2009-05-29 08:32:54 +00:00
|
|
|
}
|
2016-05-13 02:05:06 +00:00
|
|
|
else if(effect)
|
2011-07-16 09:41:02 +00:00
|
|
|
{
|
2016-05-13 01:26:33 +00:00
|
|
|
memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props));
|
2016-05-15 08:19:05 +00:00
|
|
|
UpdateEffectSlotProps(EffectSlot);
|
2011-07-16 09:41:02 +00:00
|
|
|
}
|
2012-03-13 21:58:34 +00:00
|
|
|
|
|
|
|
return AL_NO_ERROR;
|
Implement AL_EFFECT_REVERB
Here is a quick description of how the reverb effect works:
+--->---+*(4)
| V new sample
+-----+---+---+ |
|extra|ltr|ref| <- +*(1)
+-----+---+---+
(3,5)*| |*(2)
+-->|
V
out sample
1) Apply master reverb gain to incoming sample and place it at the head of the
buffer. The master reverb gainhf was already applied when the source was
initially mixed.
2) Copy the delayed reflection sample to an output sample and apply the
reflection gain.
3) Apply the late reverb gain to the late reverb sample
4) Copy the end of the buffer, applying a decay gain and the decay hf ratio,
and add to the late reverb.
5) Copy the late reverb sample, adding to the output sample.
Then the head and sampling points are shifted forward, and done again for each
new sample. The extra buffer length is determined by the Reverb Density
property. A value of 0 gives a length of 0.1 seconds (long, with fairly
distinct echos) , and 1 gives 0.075 seconds (short, indistinct echos).
The decay gain is calculated such that after a number of loops to satisfy the
Decay Time, a sample will be 1/32768th as powerful (virtually insignificant to
the resulting output, and only getting further reduced). It is calculated as:
DecayGain = pow(1.0f/32768.0f, 1.0/(DecayTime/ExtraLength));
Things to note: Reverb Diffusion is not currently handled, nor is Decay HF
Limit. Decay HF Ratios above 1 probably give incorrect results. Also, this
method likely sucks, but it's the best I can come up with before release. :)
2008-01-19 05:25:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-13 01:26:33 +00:00
|
|
|
void ALeffectState_Destruct(ALeffectState *UNUSED(state))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-21 00:23:15 +00:00
|
|
|
ALenum InitEffectSlot(ALeffectslot *slot)
|
|
|
|
{
|
2013-05-21 19:47:18 +00:00
|
|
|
ALeffectStateFactory *factory;
|
2012-01-21 00:23:15 +00:00
|
|
|
|
2016-05-13 01:26:33 +00:00
|
|
|
slot->Effect.Type = AL_EFFECT_NULL;
|
2013-05-26 05:07:31 +00:00
|
|
|
|
2013-05-21 19:47:18 +00:00
|
|
|
factory = getFactoryByType(AL_EFFECT_NULL);
|
2016-05-13 01:26:33 +00:00
|
|
|
if(!(slot->Effect.State=V0(factory,create)()))
|
2012-01-21 00:23:15 +00:00
|
|
|
return AL_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
slot->Gain = 1.0;
|
|
|
|
slot->AuxSendAuto = AL_TRUE;
|
2014-05-14 09:47:07 +00:00
|
|
|
InitRef(&slot->ref, 0);
|
2012-01-21 00:23:15 +00:00
|
|
|
|
2016-05-13 01:26:33 +00:00
|
|
|
ATOMIC_INIT(&slot->Update, NULL);
|
|
|
|
ATOMIC_INIT(&slot->FreeList, NULL);
|
|
|
|
|
|
|
|
slot->Params.Gain = 1.0f;
|
|
|
|
slot->Params.AuxSendAuto = AL_TRUE;
|
|
|
|
slot->Params.EffectState = slot->Effect.State;
|
|
|
|
slot->Params.RoomRolloff = 0.0f;
|
|
|
|
slot->Params.DecayTime = 0.0f;
|
|
|
|
slot->Params.AirAbsorptionGainHF = 1.0f;
|
|
|
|
|
2012-01-21 00:23:15 +00:00
|
|
|
return AL_NO_ERROR;
|
|
|
|
}
|
|
|
|
|
2016-05-13 01:26:33 +00:00
|
|
|
void DeinitEffectSlot(ALeffectslot *slot)
|
|
|
|
{
|
|
|
|
struct ALeffectslotProps *props;
|
2016-05-15 20:44:32 +00:00
|
|
|
ALeffectState *state;
|
2016-05-13 01:26:33 +00:00
|
|
|
size_t count = 0;
|
|
|
|
|
|
|
|
props = ATOMIC_LOAD(&slot->Update);
|
|
|
|
if(props)
|
|
|
|
{
|
2016-05-13 07:23:03 +00:00
|
|
|
state = ATOMIC_LOAD(&props->State, almemory_order_relaxed);
|
2016-05-15 08:19:05 +00:00
|
|
|
if(state != slot->Params.EffectState)
|
|
|
|
DELETE_OBJ(state);
|
2016-05-13 01:26:33 +00:00
|
|
|
TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
|
|
|
|
al_free(props);
|
|
|
|
}
|
|
|
|
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
|
|
|
|
while(props)
|
|
|
|
{
|
|
|
|
struct ALeffectslotProps *next;
|
2016-05-13 07:23:03 +00:00
|
|
|
state = ATOMIC_LOAD(&props->State, almemory_order_relaxed);
|
2016-05-13 01:26:33 +00:00
|
|
|
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
|
2016-05-13 07:23:03 +00:00
|
|
|
DELETE_OBJ(state);
|
2016-05-13 01:26:33 +00:00
|
|
|
al_free(props);
|
|
|
|
props = next;
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
|
|
|
|
|
|
|
|
DELETE_OBJ(slot->Params.EffectState);
|
|
|
|
}
|
|
|
|
|
2016-05-15 08:19:05 +00:00
|
|
|
void UpdateEffectSlotProps(ALeffectslot *slot)
|
2016-05-13 01:26:33 +00:00
|
|
|
{
|
|
|
|
struct ALeffectslotProps *props;
|
|
|
|
ALeffectState *oldstate;
|
|
|
|
|
2016-05-15 20:44:32 +00:00
|
|
|
props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL);
|
|
|
|
if(props)
|
|
|
|
{
|
|
|
|
/* If there was an unapplied update, check if its state object is the
|
|
|
|
* same as the current in-use one, or the one that will be set. If
|
|
|
|
* neither, delete it.
|
|
|
|
*/
|
|
|
|
oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed);
|
|
|
|
if(oldstate != slot->Params.EffectState && oldstate != slot->Effect.State)
|
|
|
|
DELETE_OBJ(oldstate);
|
|
|
|
}
|
2016-05-13 01:26:33 +00:00
|
|
|
else
|
|
|
|
{
|
2016-05-15 20:44:32 +00:00
|
|
|
/* Get an unused property container, or allocate a new one as needed. */
|
|
|
|
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
|
|
|
|
if(!props)
|
|
|
|
props = al_calloc(16, sizeof(*props));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
struct ALeffectslotProps *next;
|
|
|
|
do {
|
|
|
|
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
|
|
|
|
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*,
|
|
|
|
&slot->FreeList, &props, next, almemory_order_seq_cst,
|
|
|
|
almemory_order_consume) == 0);
|
|
|
|
}
|
2016-05-13 01:26:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy in current property values. */
|
|
|
|
ATOMIC_STORE(&props->Gain, slot->Gain, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->AuxSendAuto, slot->AuxSendAuto, almemory_order_relaxed);
|
|
|
|
|
|
|
|
ATOMIC_STORE(&props->Type, slot->Effect.Type, almemory_order_relaxed);
|
|
|
|
memcpy(&props->Props, &slot->Effect.Props, sizeof(props->Props));
|
|
|
|
/* Swap out any stale effect state object there may be in the container, to
|
|
|
|
* delete it.
|
|
|
|
*/
|
2016-05-15 08:19:05 +00:00
|
|
|
oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State,
|
|
|
|
almemory_order_relaxed);
|
2016-05-13 01:26:33 +00:00
|
|
|
|
|
|
|
/* Set the new container for updating internal parameters. */
|
|
|
|
props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, props,
|
|
|
|
almemory_order_acq_rel);
|
|
|
|
if(props)
|
|
|
|
{
|
|
|
|
/* If there was an unused update container, put it back in the
|
|
|
|
* freelist.
|
|
|
|
*/
|
|
|
|
struct ALeffectslotProps *first = ATOMIC_LOAD(&slot->FreeList);
|
|
|
|
do {
|
|
|
|
ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
|
|
|
|
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*,
|
|
|
|
&slot->FreeList, &first, props) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
DELETE_OBJ(oldstate);
|
|
|
|
}
|
|
|
|
|
2008-01-16 00:22:39 +00:00
|
|
|
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2010-05-12 09:20:14 +00:00
|
|
|
ALsizei pos;
|
|
|
|
for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
|
2007-12-18 01:43:19 +00:00
|
|
|
{
|
2010-05-12 09:20:14 +00:00
|
|
|
ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
|
|
|
|
Context->EffectSlotMap.array[pos].value = NULL;
|
2007-12-18 01:43:19 +00:00
|
|
|
|
2016-05-13 01:26:33 +00:00
|
|
|
DeinitEffectSlot(temp);
|
Implement AL_EFFECT_REVERB
Here is a quick description of how the reverb effect works:
+--->---+*(4)
| V new sample
+-----+---+---+ |
|extra|ltr|ref| <- +*(1)
+-----+---+---+
(3,5)*| |*(2)
+-->|
V
out sample
1) Apply master reverb gain to incoming sample and place it at the head of the
buffer. The master reverb gainhf was already applied when the source was
initially mixed.
2) Copy the delayed reflection sample to an output sample and apply the
reflection gain.
3) Apply the late reverb gain to the late reverb sample
4) Copy the end of the buffer, applying a decay gain and the decay hf ratio,
and add to the late reverb.
5) Copy the late reverb sample, adding to the output sample.
Then the head and sampling points are shifted forward, and done again for each
new sample. The extra buffer length is determined by the Reverb Density
property. A value of 0 gives a length of 0.1 seconds (long, with fairly
distinct echos) , and 1 gives 0.075 seconds (short, indistinct echos).
The decay gain is calculated such that after a number of loops to satisfy the
Decay Time, a sample will be 1/32768th as powerful (virtually insignificant to
the resulting output, and only getting further reduced). It is calculated as:
DecayGain = pow(1.0f/32768.0f, 1.0/(DecayTime/ExtraLength));
Things to note: Reverb Diffusion is not currently handled, nor is Decay HF
Limit. Decay HF Ratios above 1 probably give incorrect results. Also, this
method likely sucks, but it's the best I can come up with before release. :)
2008-01-19 05:25:40 +00:00
|
|
|
|
2012-04-20 05:28:01 +00:00
|
|
|
FreeThunkEntry(temp->id);
|
2007-12-18 01:43:19 +00:00
|
|
|
memset(temp, 0, sizeof(ALeffectslot));
|
2012-09-27 01:00:38 +00:00
|
|
|
al_free(temp);
|
2007-12-18 01:43:19 +00:00
|
|
|
}
|
|
|
|
}
|