openal-soft updates

This commit is contained in:
rextimmy 2018-05-09 20:48:18 +10:00
parent d6f6bc65a5
commit 925d8b27cf
149 changed files with 22293 additions and 16887 deletions

View file

@ -4,6 +4,7 @@
#include "alMain.h"
#include "alEffect.h"
#include "atomic.h"
#include "align.h"
#ifdef __cplusplus
@ -18,7 +19,7 @@ typedef struct ALeffectState {
const struct ALeffectStateVtable *vtbl;
ALfloat (*OutBuffer)[BUFFERSIZE];
ALuint OutChannels;
ALsizei OutChannels;
} ALeffectState;
void ALeffectState_Construct(ALeffectState *state);
@ -28,17 +29,22 @@ struct ALeffectStateVtable {
void (*const Destruct)(ALeffectState *state);
ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
void (*const update)(ALeffectState *state, const ALCdevice *device, const struct ALeffectslot *slot, const union ALeffectProps *props);
void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels);
void (*const update)(ALeffectState *state, const ALCcontext *context, const struct ALeffectslot *slot, const union ALeffectProps *props);
void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei numChannels);
void (*const Delete)(void *ptr);
};
/* Small hack to use a pointer-to-array types as a normal argument type.
* Shouldn't be used directly.
*/
typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
#define DEFINE_ALEFFECTSTATE_VTABLE(T) \
DECLARE_THUNK(T, ALeffectState, void, Destruct) \
DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \
DECLARE_THUNK3(T, ALeffectState, void, update, const ALCdevice*, const ALeffectslot*, const ALeffectProps*) \
DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \
DECLARE_THUNK3(T, ALeffectState, void, update, const ALCcontext*, const ALeffectslot*, const ALeffectProps*) \
DECLARE_THUNK4(T, ALeffectState, void, process, ALsizei, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALsizei) \
static void T##_ALeffectState_Delete(void *ptr) \
{ return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \
\
@ -53,43 +59,48 @@ static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \
}
struct ALeffectStateFactoryVtable;
struct EffectStateFactoryVtable;
typedef struct ALeffectStateFactory {
const struct ALeffectStateFactoryVtable *vtbl;
} ALeffectStateFactory;
typedef struct EffectStateFactory {
const struct EffectStateFactoryVtable *vtab;
} EffectStateFactory;
struct ALeffectStateFactoryVtable {
ALeffectState *(*const create)(ALeffectStateFactory *factory);
struct EffectStateFactoryVtable {
ALeffectState *(*const create)(EffectStateFactory *factory);
};
#define EffectStateFactory_create(x) ((x)->vtab->create((x)))
#define DEFINE_ALEFFECTSTATEFACTORY_VTABLE(T) \
DECLARE_THUNK(T, ALeffectStateFactory, ALeffectState*, create) \
#define DEFINE_EFFECTSTATEFACTORY_VTABLE(T) \
DECLARE_THUNK(T, EffectStateFactory, ALeffectState*, create) \
\
static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = { \
T##_ALeffectStateFactory_create, \
static const struct EffectStateFactoryVtable T##_EffectStateFactory_vtable = { \
T##_EffectStateFactory_create, \
}
#define MAX_EFFECT_CHANNELS (4)
struct ALeffectslotProps {
ATOMIC(ALfloat) Gain;
ATOMIC(ALboolean) AuxSendAuto;
struct ALeffectslotArray {
ALsizei count;
struct ALeffectslot *slot[];
};
ATOMIC(ALenum) Type;
struct ALeffectslotProps {
ALfloat Gain;
ALboolean AuxSendAuto;
ALenum Type;
ALeffectProps Props;
ATOMIC(ALeffectState*) State;
ALeffectState *State;
ATOMIC(struct ALeffectslotProps*) next;
};
typedef struct ALeffectslot {
ALboolean NeedsUpdate;
ALfloat Gain;
ALboolean AuxSendAuto;
@ -100,81 +111,70 @@ typedef struct ALeffectslot {
ALeffectState *State;
} Effect;
ATOMIC_FLAG PropsClean;
RefCount ref;
ATOMIC(struct ALeffectslotProps*) Update;
ATOMIC(struct ALeffectslotProps*) FreeList;
struct {
ALfloat Gain;
ALboolean AuxSendAuto;
ALenum EffectType;
ALeffectProps EffectProps;
ALeffectState *EffectState;
ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */
ALfloat DecayTime;
ALfloat DecayLFRatio;
ALfloat DecayHFRatio;
ALboolean DecayHFLimit;
ALfloat AirAbsorptionGainHF;
} Params;
/* Self ID */
ALuint id;
ALuint NumChannels;
ALsizei NumChannels;
BFChannelConfig ChanMap[MAX_EFFECT_CHANNELS];
/* Wet buffer configuration is ACN channel order with N3D scaling:
* * Channel 0 is the unattenuated mono signal.
* * Channel 1 is OpenAL -X
* * Channel 2 is OpenAL Y
* * Channel 3 is OpenAL -Z
* * Channel 1 is OpenAL -X * sqrt(3)
* * Channel 2 is OpenAL Y * sqrt(3)
* * Channel 3 is OpenAL -Z * sqrt(3)
* Consequently, effects that only want to work with mono input can use
* channel 0 by itself. Effects that want multichannel can process the
* ambisonics signal and make a B-Format pan (ComputeFirstOrderGains) for
* first-order device output (FOAOut).
*/
alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE];
ATOMIC(struct ALeffectslot*) next;
} ALeffectslot;
inline void LockEffectSlotsRead(ALCcontext *context)
{ LockUIntMapRead(&context->EffectSlotMap); }
inline void UnlockEffectSlotsRead(ALCcontext *context)
{ UnlockUIntMapRead(&context->EffectSlotMap); }
inline void LockEffectSlotsWrite(ALCcontext *context)
{ LockUIntMapWrite(&context->EffectSlotMap); }
inline void UnlockEffectSlotsWrite(ALCcontext *context)
{ UnlockUIntMapWrite(&context->EffectSlotMap); }
inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
{ return (struct ALeffectslot*)LookupUIntMapKeyNoLock(&context->EffectSlotMap, id); }
inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id)
{ return (struct ALeffectslot*)RemoveUIntMapKeyNoLock(&context->EffectSlotMap, id); }
ALenum InitEffectSlot(ALeffectslot *slot);
void DeinitEffectSlot(ALeffectslot *slot);
void UpdateEffectSlotProps(ALeffectslot *slot);
void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context);
void UpdateAllEffectSlotProps(ALCcontext *context);
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
ALeffectStateFactory *ALnullStateFactory_getFactory(void);
ALeffectStateFactory *ALreverbStateFactory_getFactory(void);
ALeffectStateFactory *ALchorusStateFactory_getFactory(void);
ALeffectStateFactory *ALcompressorStateFactory_getFactory(void);
ALeffectStateFactory *ALdistortionStateFactory_getFactory(void);
ALeffectStateFactory *ALechoStateFactory_getFactory(void);
ALeffectStateFactory *ALequalizerStateFactory_getFactory(void);
ALeffectStateFactory *ALflangerStateFactory_getFactory(void);
ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void);
EffectStateFactory *NullStateFactory_getFactory(void);
EffectStateFactory *ReverbStateFactory_getFactory(void);
EffectStateFactory *ChorusStateFactory_getFactory(void);
EffectStateFactory *CompressorStateFactory_getFactory(void);
EffectStateFactory *DistortionStateFactory_getFactory(void);
EffectStateFactory *EchoStateFactory_getFactory(void);
EffectStateFactory *EqualizerStateFactory_getFactory(void);
EffectStateFactory *FlangerStateFactory_getFactory(void);
EffectStateFactory *ModulatorStateFactory_getFactory(void);
EffectStateFactory *PshifterStateFactory_getFactory(void);
ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void);
EffectStateFactory *DedicatedStateFactory_getFactory(void);
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect);
ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
void InitEffectFactoryMap(void);
void DeinitEffectFactoryMap(void);
void ALeffectState_DecRef(ALeffectState *state);
#ifdef __cplusplus
}

View file

@ -1,7 +1,13 @@
#ifndef _AL_BUFFER_H_
#define _AL_BUFFER_H_
#include "alMain.h"
#include "AL/alc.h"
#include "AL/al.h"
#include "AL/alext.h"
#include "inprogext.h"
#include "atomic.h"
#include "rwlock.h"
#ifdef __cplusplus
extern "C" {
@ -9,36 +15,30 @@ extern "C" {
/* User formats */
enum UserFmtType {
UserFmtByte = AL_BYTE_SOFT,
UserFmtUByte = AL_UNSIGNED_BYTE_SOFT,
UserFmtShort = AL_SHORT_SOFT,
UserFmtUShort = AL_UNSIGNED_SHORT_SOFT,
UserFmtInt = AL_INT_SOFT,
UserFmtUInt = AL_UNSIGNED_INT_SOFT,
UserFmtFloat = AL_FLOAT_SOFT,
UserFmtDouble = AL_DOUBLE_SOFT,
UserFmtByte3 = AL_BYTE3_SOFT,
UserFmtUByte3 = AL_UNSIGNED_BYTE3_SOFT,
UserFmtMulaw = AL_MULAW_SOFT,
UserFmtAlaw = 0x10000000,
UserFmtUByte,
UserFmtShort,
UserFmtFloat,
UserFmtDouble,
UserFmtMulaw,
UserFmtAlaw,
UserFmtIMA4,
UserFmtMSADPCM,
};
enum UserFmtChannels {
UserFmtMono = AL_MONO_SOFT,
UserFmtStereo = AL_STEREO_SOFT,
UserFmtRear = AL_REAR_SOFT,
UserFmtQuad = AL_QUAD_SOFT,
UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */
UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */
UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */
UserFmtBFormat2D = AL_BFORMAT2D_SOFT, /* WXY */
UserFmtBFormat3D = AL_BFORMAT3D_SOFT, /* WXYZ */
UserFmtMono,
UserFmtStereo,
UserFmtRear,
UserFmtQuad,
UserFmtX51, /* (WFX order) */
UserFmtX61, /* (WFX order) */
UserFmtX71, /* (WFX order) */
UserFmtBFormat2D, /* WXY */
UserFmtBFormat3D, /* WXYZ */
};
ALuint BytesFromUserFmt(enum UserFmtType type);
ALuint ChannelsFromUserFmt(enum UserFmtChannels chans);
inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type)
ALsizei BytesFromUserFmt(enum UserFmtType type);
ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans);
inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type)
{
return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type);
}
@ -46,9 +46,12 @@ inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType
/* Storable formats */
enum FmtType {
FmtByte = UserFmtByte,
FmtShort = UserFmtShort,
FmtFloat = UserFmtFloat,
FmtUByte = UserFmtUByte,
FmtShort = UserFmtShort,
FmtFloat = UserFmtFloat,
FmtDouble = UserFmtDouble,
FmtMulaw = UserFmtMulaw,
FmtAlaw = UserFmtAlaw,
};
enum FmtChannels {
FmtMono = UserFmtMono,
@ -63,9 +66,9 @@ enum FmtChannels {
};
#define MAX_INPUT_CHANNELS (8)
ALuint BytesFromFmt(enum FmtType type);
ALuint ChannelsFromFmt(enum FmtChannels chans);
inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
ALsizei BytesFromFmt(enum FmtType type);
ALsizei ChannelsFromFmt(enum FmtChannels chans);
inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
{
return ChannelsFromFmt(chans) * BytesFromFmt(type);
}
@ -74,53 +77,35 @@ inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
typedef struct ALbuffer {
ALvoid *data;
ALsizei Frequency;
ALenum Format;
ALsizei SampleLen;
ALsizei Frequency;
ALbitfieldSOFT Access;
ALsizei SampleLen;
enum FmtChannels FmtChannels;
enum FmtType FmtType;
ALuint BytesAlloc;
ALsizei BytesAlloc;
enum UserFmtChannels OriginalChannels;
enum UserFmtType OriginalType;
ALsizei OriginalSize;
ALsizei OriginalAlign;
enum UserFmtType OriginalType;
ALsizei OriginalSize;
ALsizei OriginalAlign;
ALsizei LoopStart;
ALsizei LoopEnd;
ALsizei LoopStart;
ALsizei LoopEnd;
ATOMIC(ALsizei) UnpackAlign;
ATOMIC(ALsizei) PackAlign;
ALbitfieldSOFT MappedAccess;
ALsizei MappedOffset;
ALsizei MappedSize;
/* Number of times buffer was attached to a source (deletion can only occur when 0) */
RefCount ref;
RWLock lock;
/* Self ID */
ALuint id;
} ALbuffer;
ALbuffer *NewBuffer(ALCcontext *context);
void DeleteBuffer(ALCdevice *device, ALbuffer *buffer);
ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc);
inline void LockBuffersRead(ALCdevice *device)
{ LockUIntMapRead(&device->BufferMap); }
inline void UnlockBuffersRead(ALCdevice *device)
{ UnlockUIntMapRead(&device->BufferMap); }
inline void LockBuffersWrite(ALCdevice *device)
{ LockUIntMapWrite(&device->BufferMap); }
inline void UnlockBuffersWrite(ALCdevice *device)
{ UnlockUIntMapWrite(&device->BufferMap); }
inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
{ return (struct ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); }
inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id)
{ return (struct ALbuffer*)RemoveUIntMapKeyNoLock(&device->BufferMap, id); }
ALvoid ReleaseALBuffers(ALCdevice *device);
#ifdef __cplusplus

View file

@ -10,23 +10,32 @@ extern "C" {
struct ALeffect;
enum {
EAXREVERB = 0,
REVERB,
CHORUS,
COMPRESSOR,
DISTORTION,
ECHO,
EQUALIZER,
FLANGER,
MODULATOR,
DEDICATED,
EAXREVERB_EFFECT = 0,
REVERB_EFFECT,
CHORUS_EFFECT,
COMPRESSOR_EFFECT,
DISTORTION_EFFECT,
ECHO_EFFECT,
EQUALIZER_EFFECT,
FLANGER_EFFECT,
MODULATOR_EFFECT,
PSHIFTER_EFFECT,
DEDICATED_EFFECT,
MAX_EFFECTS
};
extern ALboolean DisabledEffects[MAX_EFFECTS];
extern ALfloat ReverbBoost;
extern ALboolean EmulateEAXReverb;
struct EffectList {
const char name[16];
int type;
ALenum val;
};
#define EFFECTLIST_SIZE 12
extern const struct EffectList EffectList[EFFECTLIST_SIZE];
struct ALeffectVtable {
void (*const setParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val);
@ -58,6 +67,7 @@ extern const struct ALeffectVtable ALequalizer_vtable;
extern const struct ALeffectVtable ALflanger_vtable;
extern const struct ALeffectVtable ALmodulator_vtable;
extern const struct ALeffectVtable ALnull_vtable;
extern const struct ALeffectVtable ALpshifter_vtable;
extern const struct ALeffectVtable ALdedicated_vtable;
@ -98,7 +108,7 @@ typedef union ALeffectProps {
ALfloat Depth;
ALfloat Feedback;
ALfloat Delay;
} Chorus;
} Chorus; /* Also Flanger */
struct {
ALboolean OnOff;
@ -135,21 +145,17 @@ typedef union ALeffectProps {
ALfloat HighGain;
} Equalizer;
struct {
ALint Waveform;
ALint Phase;
ALfloat Rate;
ALfloat Depth;
ALfloat Feedback;
ALfloat Delay;
} Flanger;
struct {
ALfloat Frequency;
ALfloat HighPassCutoff;
ALint Waveform;
} Modulator;
struct {
ALint CoarseTune;
ALint FineTune;
} Pshifter;
struct {
ALfloat Gain;
} Dedicated;
@ -161,33 +167,27 @@ typedef struct ALeffect {
ALeffectProps Props;
const struct ALeffectVtable *vtbl;
const struct ALeffectVtable *vtab;
/* Self ID */
ALuint id;
} ALeffect;
inline void LockEffectsRead(ALCdevice *device)
{ LockUIntMapRead(&device->EffectMap); }
inline void UnlockEffectsRead(ALCdevice *device)
{ UnlockUIntMapRead(&device->EffectMap); }
inline void LockEffectsWrite(ALCdevice *device)
{ LockUIntMapWrite(&device->EffectMap); }
inline void UnlockEffectsWrite(ALCdevice *device)
{ UnlockUIntMapWrite(&device->EffectMap); }
inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id)
{ return (struct ALeffect*)LookupUIntMapKeyNoLock(&device->EffectMap, id); }
inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id)
{ return (struct ALeffect*)RemoveUIntMapKeyNoLock(&device->EffectMap, id); }
#define ALeffect_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v))
#define ALeffect_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v))
#define ALeffect_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v))
#define ALeffect_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v))
#define ALeffect_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v))
#define ALeffect_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v))
#define ALeffect_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v))
#define ALeffect_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v))
inline ALboolean IsReverbEffect(ALenum type)
{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; }
ALenum InitEffect(ALeffect *effect);
ALvoid ReleaseALEffects(ALCdevice *device);
void InitEffect(ALeffect *effect);
void ReleaseALEffects(ALCdevice *device);
ALvoid LoadReverbPreset(const char *name, ALeffect *effect);
void LoadReverbPreset(const char *name, ALeffect *effect);
#ifdef __cplusplus
}

View file

@ -2,6 +2,7 @@
#define _AL_ERROR_H_
#include "alMain.h"
#include "logging.h"
#ifdef __cplusplus
extern "C" {
@ -9,23 +10,18 @@ extern "C" {
extern ALboolean TrapALError;
ALvoid alSetError(ALCcontext *Context, ALenum errorCode);
void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4);
#define SET_ERROR_AND_RETURN(ctx, err) do { \
alSetError((ctx), (err)); \
return; \
} while(0)
#define SET_ERROR_AND_RETURN_VALUE(ctx, err, val) do { \
alSetError((ctx), (err)); \
return (val); \
} while(0)
#define SET_ERROR_AND_GOTO(ctx, err, lbl) do { \
alSetError((ctx), (err)); \
#define SETERR_GOTO(ctx, err, lbl, ...) do { \
alSetError((ctx), (err), __VA_ARGS__); \
goto lbl; \
} while(0)
#define SETERR_RETURN(ctx, err, retval, ...) do { \
alSetError((ctx), (err), __VA_ARGS__); \
return retval; \
} while(0)
#ifdef __cplusplus
}
#endif

View file

@ -1,9 +1,8 @@
#ifndef _AL_FILTER_H_
#define _AL_FILTER_H_
#include "alMain.h"
#include "math_defs.h"
#include "AL/alc.h"
#include "AL/al.h"
#ifdef __cplusplus
extern "C" {
@ -13,90 +12,27 @@ extern "C" {
#define HIGHPASSFREQREF (250.0f)
/* Filters implementation is based on the "Cookbook formulae for audio
* EQ biquad filter coefficients" by Robert Bristow-Johnson
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
*/
/* Implementation note: For the shelf filters, the specified gain is for the
* reference frequency, which is the centerpoint of the transition band. This
* better matches EFX filter design. To set the gain for the shelf itself, use
* the square root of the desired linear gain (or halve the dB gain).
*/
struct ALfilter;
typedef enum ALfilterType {
/** EFX-style low-pass filter, specifying a gain and reference frequency. */
ALfilterType_HighShelf,
/** EFX-style high-pass filter, specifying a gain and reference frequency. */
ALfilterType_LowShelf,
/** Peaking filter, specifying a gain and reference frequency. */
ALfilterType_Peaking,
typedef struct ALfilterVtable {
void (*const setParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val);
void (*const setParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals);
void (*const setParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val);
void (*const setParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals);
/** Low-pass cut-off filter, specifying a cut-off frequency. */
ALfilterType_LowPass,
/** High-pass cut-off filter, specifying a cut-off frequency. */
ALfilterType_HighPass,
/** Band-pass filter, specifying a center frequency. */
ALfilterType_BandPass,
} ALfilterType;
void (*const getParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val);
void (*const getParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals);
void (*const getParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val);
void (*const getParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals);
} ALfilterVtable;
typedef struct ALfilterState {
ALfloat x[2]; /* History of two last input samples */
ALfloat y[2]; /* History of two last output samples */
ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */
ALfloat b0, b1, b2; /* Transfer function coefficients "b" */
} ALfilterState;
/* Currently only a C-based filter process method is implemented. */
#define ALfilterState_process ALfilterState_processC
/* Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the
* reference gain and shelf slope parameter.
* 0 < gain
* 0 < slope <= 1
*/
inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope)
{
return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f);
#define DEFINE_ALFILTER_VTABLE(T) \
const struct ALfilterVtable T##_vtable = { \
T##_setParami, T##_setParamiv, \
T##_setParamf, T##_setParamfv, \
T##_getParami, T##_getParamiv, \
T##_getParamf, T##_getParamfv, \
}
/* Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the frequency
* multiple (i.e. ref_freq / sampling_freq) and bandwidth.
* 0 < freq_mult < 0.5.
*/
inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth)
{
ALfloat w0 = F_TAU * freq_mult;
return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0));
}
inline void ALfilterState_clear(ALfilterState *filter)
{
filter->x[0] = 0.0f;
filter->x[1] = 0.0f;
filter->y[0] = 0.0f;
filter->y[1] = 0.0f;
}
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ);
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALuint numsamples);
inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALuint numsamples)
{
if(numsamples >= 2)
{
filter->x[1] = src[numsamples-2];
filter->x[0] = src[numsamples-1];
filter->y[1] = src[numsamples-2];
filter->y[0] = src[numsamples-1];
}
else if(numsamples == 1)
{
filter->x[1] = filter->x[0];
filter->x[0] = src[0];
filter->y[1] = filter->y[0];
filter->y[0] = src[0];
}
}
typedef struct ALfilter {
// Filter type (AL_FILTER_NULL, ...)
@ -108,45 +44,21 @@ typedef struct ALfilter {
ALfloat GainLF;
ALfloat LFReference;
void (*SetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val);
void (*SetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals);
void (*SetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val);
void (*SetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals);
void (*GetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val);
void (*GetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals);
void (*GetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val);
void (*GetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals);
const struct ALfilterVtable *vtab;
/* Self ID */
ALuint id;
} ALfilter;
#define ALfilter_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v))
#define ALfilter_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v))
#define ALfilter_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v))
#define ALfilter_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v))
#define ALfilter_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v))
#define ALfilter_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v))
#define ALfilter_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v))
#define ALfilter_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v))
#define ALfilter_SetParami(x, c, p, v) ((x)->SetParami((x),(c),(p),(v)))
#define ALfilter_SetParamiv(x, c, p, v) ((x)->SetParamiv((x),(c),(p),(v)))
#define ALfilter_SetParamf(x, c, p, v) ((x)->SetParamf((x),(c),(p),(v)))
#define ALfilter_SetParamfv(x, c, p, v) ((x)->SetParamfv((x),(c),(p),(v)))
#define ALfilter_GetParami(x, c, p, v) ((x)->GetParami((x),(c),(p),(v)))
#define ALfilter_GetParamiv(x, c, p, v) ((x)->GetParamiv((x),(c),(p),(v)))
#define ALfilter_GetParamf(x, c, p, v) ((x)->GetParamf((x),(c),(p),(v)))
#define ALfilter_GetParamfv(x, c, p, v) ((x)->GetParamfv((x),(c),(p),(v)))
inline void LockFiltersRead(ALCdevice *device)
{ LockUIntMapRead(&device->FilterMap); }
inline void UnlockFiltersRead(ALCdevice *device)
{ UnlockUIntMapRead(&device->FilterMap); }
inline void LockFiltersWrite(ALCdevice *device)
{ LockUIntMapWrite(&device->FilterMap); }
inline void UnlockFiltersWrite(ALCdevice *device)
{ UnlockUIntMapWrite(&device->FilterMap); }
inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id)
{ return (struct ALfilter*)LookupUIntMapKeyNoLock(&device->FilterMap, id); }
inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id)
{ return (struct ALfilter*)RemoveUIntMapKeyNoLock(&device->FilterMap, id); }
ALvoid ReleaseALFilters(ALCdevice *device);
void ReleaseALFilters(ALCdevice *device);
#ifdef __cplusplus
}

View file

@ -8,40 +8,40 @@
extern "C" {
#endif
struct ALlistenerProps {
ATOMIC(ALfloat) Position[3];
ATOMIC(ALfloat) Velocity[3];
ATOMIC(ALfloat) Forward[3];
ATOMIC(ALfloat) Up[3];
ATOMIC(ALfloat) Gain;
ATOMIC(ALfloat) MetersPerUnit;
struct ALcontextProps {
ALfloat DopplerFactor;
ALfloat DopplerVelocity;
ALfloat SpeedOfSound;
ALboolean SourceDistanceModel;
enum DistanceModel DistanceModel;
ALfloat MetersPerUnit;
ATOMIC(ALfloat) DopplerFactor;
ATOMIC(ALfloat) DopplerVelocity;
ATOMIC(ALfloat) SpeedOfSound;
ATOMIC(ALboolean) SourceDistanceModel;
ATOMIC(enum DistanceModel) DistanceModel;
ATOMIC(struct ALcontextProps*) next;
};
struct ALlistenerProps {
ALfloat Position[3];
ALfloat Velocity[3];
ALfloat Forward[3];
ALfloat Up[3];
ALfloat Gain;
ATOMIC(struct ALlistenerProps*) next;
};
typedef struct ALlistener {
volatile ALfloat Position[3];
volatile ALfloat Velocity[3];
volatile ALfloat Forward[3];
volatile ALfloat Up[3];
volatile ALfloat Gain;
volatile ALfloat MetersPerUnit;
alignas(16) ALfloat Position[3];
ALfloat Velocity[3];
ALfloat Forward[3];
ALfloat Up[3];
ALfloat Gain;
ATOMIC_FLAG PropsClean;
/* Pointer to the most recent property values that are awaiting an update.
*/
ATOMIC(struct ALlistenerProps*) Update;
/* A linked list of unused property containers, free to use for future
* updates.
*/
ATOMIC(struct ALlistenerProps*) FreeList;
struct {
aluMatrixf Matrix;
aluVector Velocity;
@ -50,7 +50,8 @@ typedef struct ALlistener {
ALfloat MetersPerUnit;
ALfloat DopplerFactor;
ALfloat SpeedOfSound;
ALfloat SpeedOfSound; /* in units per sec! */
ALfloat ReverbSpeedOfSound; /* in meters per sec! */
ALboolean SourceDistanceModel;
enum DistanceModel DistanceModel;

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,14 @@
#ifndef _AL_SOURCE_H_
#define _AL_SOURCE_H_
#define MAX_SENDS 4
#include "bool.h"
#include "alMain.h"
#include "alu.h"
#include "hrtf.h"
#include "atomic.h"
#define MAX_SENDS 16
#define DEFAULT_SENDS 2
#ifdef __cplusplus
extern "C" {
@ -13,104 +16,16 @@ extern "C" {
struct ALbuffer;
struct ALsource;
struct ALsourceProps;
typedef struct ALbufferlistitem {
struct ALbuffer *buffer;
struct ALbufferlistitem *volatile next;
ATOMIC(struct ALbufferlistitem*) next;
ALsizei max_samples;
ALsizei num_buffers;
struct ALbuffer *buffers[];
} ALbufferlistitem;
struct ALsourceProps {
ATOMIC(ALfloat) Pitch;
ATOMIC(ALfloat) Gain;
ATOMIC(ALfloat) OuterGain;
ATOMIC(ALfloat) MinGain;
ATOMIC(ALfloat) MaxGain;
ATOMIC(ALfloat) InnerAngle;
ATOMIC(ALfloat) OuterAngle;
ATOMIC(ALfloat) RefDistance;
ATOMIC(ALfloat) MaxDistance;
ATOMIC(ALfloat) RollOffFactor;
ATOMIC(ALfloat) Position[3];
ATOMIC(ALfloat) Velocity[3];
ATOMIC(ALfloat) Direction[3];
ATOMIC(ALfloat) Orientation[2][3];
ATOMIC(ALboolean) HeadRelative;
ATOMIC(enum DistanceModel) DistanceModel;
ATOMIC(ALboolean) DirectChannels;
ATOMIC(ALboolean) DryGainHFAuto;
ATOMIC(ALboolean) WetGainAuto;
ATOMIC(ALboolean) WetGainHFAuto;
ATOMIC(ALfloat) OuterGainHF;
ATOMIC(ALfloat) AirAbsorptionFactor;
ATOMIC(ALfloat) RoomRolloffFactor;
ATOMIC(ALfloat) DopplerFactor;
ATOMIC(ALfloat) StereoPan[2];
ATOMIC(ALfloat) Radius;
/** Direct filter and auxiliary send info. */
struct {
ATOMIC(ALfloat) Gain;
ATOMIC(ALfloat) GainHF;
ATOMIC(ALfloat) HFReference;
ATOMIC(ALfloat) GainLF;
ATOMIC(ALfloat) LFReference;
} Direct;
struct {
ATOMIC(struct ALeffectslot*) Slot;
ATOMIC(ALfloat) Gain;
ATOMIC(ALfloat) GainHF;
ATOMIC(ALfloat) HFReference;
ATOMIC(ALfloat) GainLF;
ATOMIC(ALfloat) LFReference;
} Send[MAX_SENDS];
ATOMIC(struct ALsourceProps*) next;
};
typedef struct ALvoice {
struct ALsourceProps Props;
struct ALsource *volatile Source;
/** Current target parameters used for mixing. */
ALint Step;
/* If not 'moving', gain/coefficients are set directly without fading. */
ALboolean Moving;
ALboolean IsHrtf;
ALuint Offset; /* Number of output samples mixed since starting. */
alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES];
BsincState SincState;
struct {
ALfloat (*Buffer)[BUFFERSIZE];
ALuint Channels;
} DirectOut;
struct {
ALfloat (*Buffer)[BUFFERSIZE];
ALuint Channels;
} SendOut[MAX_SENDS];
struct {
DirectParams Direct;
SendParams Send[MAX_SENDS];
} Chan[MAX_INPUT_CHANNELS];
} ALvoice;
typedef struct ALsource {
/** Source properties. */
ALfloat Pitch;
@ -122,14 +37,17 @@ typedef struct ALsource {
ALfloat OuterAngle;
ALfloat RefDistance;
ALfloat MaxDistance;
ALfloat RollOffFactor;
ALfloat RolloffFactor;
ALfloat Position[3];
ALfloat Velocity[3];
ALfloat Direction[3];
ALfloat Orientation[2][3];
ALboolean HeadRelative;
ALboolean Looping;
enum DistanceModel DistanceModel;
enum Resampler Resampler;
ALboolean DirectChannels;
enum SpatializeMode Spatialize;
ALboolean DryGainHFAuto;
ALboolean WetGainAuto;
@ -162,7 +80,7 @@ typedef struct ALsource {
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Send[MAX_SENDS];
} *Send;
/**
* Last user-specified offset, and the offset type (bytes, samples, or
@ -176,51 +94,22 @@ typedef struct ALsource {
/** Source state (initial, playing, paused, or stopped) */
ALenum state;
ALenum new_state;
/** Source Buffer Queue info. */
RWLock queue_lock;
ATOMIC(ALbufferlistitem*) queue;
ATOMIC(ALbufferlistitem*) current_buffer;
/** Source Buffer Queue head. */
ALbufferlistitem *queue;
/**
* Source offset in samples, relative to the currently playing buffer, NOT
* the whole queue, and the fractional (fixed-point) offset to the next
* sample.
ATOMIC_FLAG PropsClean;
/* Index into the context's Voices array. Lazily updated, only checked and
* reset when looking up the voice.
*/
ATOMIC(ALuint) position;
ATOMIC(ALuint) position_fraction;
ATOMIC(ALboolean) looping;
/** Current buffer sample info. */
ALuint NumChannels;
ALuint SampleSize;
ATOMIC(struct ALsourceProps*) Update;
ATOMIC(struct ALsourceProps*) FreeList;
ALint VoiceIdx;
/** Self ID */
ALuint id;
} ALsource;
inline void LockSourcesRead(ALCcontext *context)
{ LockUIntMapRead(&context->SourceMap); }
inline void UnlockSourcesRead(ALCcontext *context)
{ UnlockUIntMapRead(&context->SourceMap); }
inline void LockSourcesWrite(ALCcontext *context)
{ LockUIntMapWrite(&context->SourceMap); }
inline void UnlockSourcesWrite(ALCcontext *context)
{ UnlockUIntMapWrite(&context->SourceMap); }
inline struct ALsource *LookupSource(ALCcontext *context, ALuint id)
{ return (struct ALsource*)LookupUIntMapKeyNoLock(&context->SourceMap, id); }
inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id)
{ return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); }
void UpdateAllSourceProps(ALCcontext *context);
ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state);
ALboolean ApplyOffset(ALsource *Source);
ALvoid ReleaseALSources(ALCcontext *Context);

View file

@ -1,20 +0,0 @@
#ifndef ALTHUNK_H
#define ALTHUNK_H
#include "alMain.h"
#ifdef __cplusplus
extern "C" {
#endif
void ThunkInit(void);
void ThunkExit(void);
ALenum NewThunkEntry(ALuint *index);
void FreeThunkEntry(ALuint index);
#ifdef __cplusplus
}
#endif
#endif //ALTHUNK_H

View file

@ -12,35 +12,56 @@
#include "alMain.h"
#include "alBuffer.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "hrtf.h"
#include "align.h"
#include "math_defs.h"
#include "filters/defs.h"
#include "filters/nfc.h"
#define MAX_PITCH (255)
/* Maximum number of buffer samples before the current pos needed for resampling. */
#define MAX_PRE_SAMPLES 12
/* Maximum number of buffer samples after the current pos needed for resampling. */
#define MAX_POST_SAMPLES 12
/* Maximum number of samples to pad on either end of a buffer for resampling.
* Note that both the beginning and end need padding!
*/
#define MAX_RESAMPLE_PADDING 24
#ifdef __cplusplus
extern "C" {
#endif
struct BSincTable;
struct ALsource;
struct ALsourceProps;
struct ALbufferlistitem;
struct ALvoice;
struct ALeffectslot;
struct ALbuffer;
/* The number of distinct scale and phase intervals within the filter table. */
#define DITHER_RNG_SEED 22222
enum SpatializeMode {
SpatializeOff = AL_FALSE,
SpatializeOn = AL_TRUE,
SpatializeAuto = AL_AUTO_SOFT
};
enum Resampler {
PointResampler,
LinearResampler,
FIR4Resampler,
BSinc12Resampler,
BSinc24Resampler,
ResamplerMax = BSinc24Resampler
};
extern enum Resampler ResamplerDefault;
/* The number of distinct scale and phase intervals within the bsinc filter
* table.
*/
#define BSINC_SCALE_BITS 4
#define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
#define BSINC_PHASE_BITS 4
@ -52,16 +73,29 @@ struct ALbuffer;
*/
typedef struct BsincState {
ALfloat sf; /* Scale interpolation factor. */
ALuint m; /* Coefficient count. */
ALsizei m; /* Coefficient count. */
ALint l; /* Left coefficient offset. */
struct {
const ALfloat *filter; /* Filter coefficients. */
const ALfloat *scDelta; /* Scale deltas. */
const ALfloat *phDelta; /* Phase deltas. */
const ALfloat *spDelta; /* Scale-phase deltas. */
} coeffs[BSINC_PHASE_COUNT];
/* Filter coefficients, followed by the scale, phase, and scale-phase
* delta coefficients. Starting at phase index 0, each subsequent phase
* index follows contiguously.
*/
const ALfloat *filter;
} BsincState;
typedef union InterpState {
BsincState bsinc;
} InterpState;
typedef const ALfloat* (*ResamplerFunc)(const InterpState *state,
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei dstlen
);
void BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table);
extern const struct BSincTable bsinc12;
extern const struct BSincTable bsinc24;
typedef union aluVector {
alignas(16) ALfloat v[4];
@ -111,21 +145,21 @@ enum ActiveFilters {
typedef struct MixHrtfParams {
const HrtfParams *Target;
HrtfParams *Current;
struct {
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
ALint Delay[2];
} Steps;
const ALfloat (*Coeffs)[2];
ALsizei Delay[2];
ALfloat Gain;
ALfloat GainStep;
} MixHrtfParams;
typedef struct DirectParams {
enum ActiveFilters FilterType;
ALfilterState LowPass;
ALfilterState HighPass;
BiquadFilter LowPass;
BiquadFilter HighPass;
NfcFilter NFCtrlFilter;
struct {
HrtfParams Current;
HrtfParams Old;
HrtfParams Target;
HrtfState State;
} Hrtf;
@ -137,9 +171,8 @@ typedef struct DirectParams {
} DirectParams;
typedef struct SendParams {
enum ActiveFilters FilterType;
ALfilterState LowPass;
ALfilterState HighPass;
BiquadFilter LowPass;
BiquadFilter HighPass;
struct {
ALfloat Current[MAX_OUTPUT_CHANNELS];
@ -148,25 +181,150 @@ typedef struct SendParams {
} SendParams;
typedef const ALfloat* (*ResamplerFunc)(const BsincState *state,
const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen
);
struct ALvoiceProps {
ATOMIC(struct ALvoiceProps*) next;
typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans,
ALfloat Pitch;
ALfloat Gain;
ALfloat OuterGain;
ALfloat MinGain;
ALfloat MaxGain;
ALfloat InnerAngle;
ALfloat OuterAngle;
ALfloat RefDistance;
ALfloat MaxDistance;
ALfloat RolloffFactor;
ALfloat Position[3];
ALfloat Velocity[3];
ALfloat Direction[3];
ALfloat Orientation[2][3];
ALboolean HeadRelative;
enum DistanceModel DistanceModel;
enum Resampler Resampler;
ALboolean DirectChannels;
enum SpatializeMode SpatializeMode;
ALboolean DryGainHFAuto;
ALboolean WetGainAuto;
ALboolean WetGainHFAuto;
ALfloat OuterGainHF;
ALfloat AirAbsorptionFactor;
ALfloat RoomRolloffFactor;
ALfloat DopplerFactor;
ALfloat StereoPan[2];
ALfloat Radius;
/** Direct filter and auxiliary send info. */
struct {
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Direct;
struct {
struct ALeffectslot *Slot;
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Send[];
};
#define VOICE_IS_STATIC (1<<0)
#define VOICE_IS_FADING (1<<1) /* Fading sources use gain stepping for smooth transitions. */
#define VOICE_HAS_HRTF (1<<2)
#define VOICE_HAS_NFC (1<<3)
typedef struct ALvoice {
struct ALvoiceProps *Props;
ATOMIC(struct ALvoiceProps*) Update;
ATOMIC(struct ALsource*) Source;
ATOMIC(bool) Playing;
/**
* Source offset in samples, relative to the currently playing buffer, NOT
* the whole queue, and the fractional (fixed-point) offset to the next
* sample.
*/
ATOMIC(ALuint) position;
ATOMIC(ALsizei) position_fraction;
/* Current buffer queue item being played. */
ATOMIC(struct ALbufferlistitem*) current_buffer;
/* Buffer queue item to loop to at end of queue (will be NULL for non-
* looping voices).
*/
ATOMIC(struct ALbufferlistitem*) loop_buffer;
/**
* Number of channels and bytes-per-sample for the attached source's
* buffer(s).
*/
ALsizei NumChannels;
ALsizei SampleSize;
/** Current target parameters used for mixing. */
ALint Step;
ResamplerFunc Resampler;
ALuint Flags;
ALuint Offset; /* Number of output samples mixed since starting. */
alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_RESAMPLE_PADDING];
InterpState ResampleState;
struct {
enum ActiveFilters FilterType;
DirectParams Params[MAX_INPUT_CHANNELS];
ALfloat (*Buffer)[BUFFERSIZE];
ALsizei Channels;
ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1];
} Direct;
struct {
enum ActiveFilters FilterType;
SendParams Params[MAX_INPUT_CHANNELS];
ALfloat (*Buffer)[BUFFERSIZE];
ALsizei Channels;
} Send[];
} ALvoice;
void DeinitVoice(ALvoice *voice);
typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans,
ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains,
const ALfloat *TargetGains, ALuint Counter, ALuint OutPos,
ALuint BufferSize);
const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
ALsizei BufferSize);
typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains,
const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans,
ALuint InPos, ALuint BufferSize);
typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx,
const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos,
const ALuint IrSize, const MixHrtfParams *hrtfparams,
HrtfState *hrtfstate, ALuint BufferSize);
typedef void (*HrtfDirectMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE],
ALuint lidx, ALuint ridx, const ALfloat *data, ALuint Offset,
const ALuint IrSize, ALfloat (*restrict Coeffs)[2],
ALfloat (*restrict Values)[2], ALuint BufferSize);
const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans,
ALsizei InPos, ALsizei BufferSize);
typedef void (*HrtfMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, MixHrtfParams *hrtfparams,
HrtfState *hrtfstate, ALsizei BufferSize);
typedef void (*HrtfMixerBlendFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, const HrtfParams *oldparams,
MixHrtfParams *newparams, HrtfState *hrtfstate,
ALsizei BufferSize);
typedef void (*HrtfDirectMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
const ALfloat (*restrict Coeffs)[2],
ALfloat (*restrict Values)[2], ALsizei BufferSize);
#define GAIN_MIX_MAX (16.0f) /* +24dB */
@ -176,6 +334,9 @@ typedef void (*HrtfDirectMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE],
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */
/* Target gain for the reverb decay feedback reaching the decay time. */
#define REVERB_DECAY_GAIN (0.001f) /* -60 dB */
#define FRACTIONBITS (12)
#define FRACTIONONE (1<<FRACTIONBITS)
#define FRACTIONMASK (FRACTIONONE-1)
@ -223,30 +384,26 @@ inline ALuint64 maxu64(ALuint64 a, ALuint64 b)
inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
{ return minu64(max, maxu64(min, val)); }
union ResamplerCoeffs {
ALfloat FIR4[FRACTIONONE][4];
ALfloat FIR8[FRACTIONONE][8];
};
extern alignas(16) union ResamplerCoeffs ResampleCoeffs;
extern alignas(16) const ALfloat bsincTab[18840];
inline size_t minz(size_t a, size_t b)
{ return ((a > b) ? b : a); }
inline size_t maxz(size_t a, size_t b)
{ return ((a > b) ? a : b); }
inline size_t clampz(size_t val, size_t min, size_t max)
{ return minz(max, maxz(min, val)); }
inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
{
return val1 + (val2-val1)*mu;
}
inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac)
inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu)
{
const ALfloat *k = ResampleCoeffs.FIR4[frac];
return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3;
}
inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac)
{
const ALfloat *k = ResampleCoeffs.FIR8[frac];
return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3 +
k[4]*val4 + k[5]*val5 + k[6]*val6 + k[7]*val7;
ALfloat mu2 = mu*mu, mu3 = mu2*mu;
ALfloat a0 = -0.5f*mu3 + mu2 + -0.5f*mu;
ALfloat a1 = 1.5f*mu3 + -2.5f*mu2 + 1.0f;
ALfloat a2 = -1.5f*mu3 + 2.0f*mu2 + 0.5f*mu;
ALfloat a3 = 0.5f*mu3 + -0.5f*mu2;
return val1*a0 + val2*a1 + val3*a2 + val4*a3;
}
@ -256,11 +413,11 @@ enum HrtfRequestMode {
Hrtf_Disable = 2,
};
void aluInit(void);
void aluInitMixer(void);
MixerFunc SelectMixer(void);
RowMixerFunc SelectRowMixer(void);
ResamplerFunc SelectResampler(enum Resampler resampler);
/* aluInitRenderer
*
@ -271,6 +428,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
void aluInitEffectPanning(struct ALeffectslot *slot);
void aluSelectPostProcess(ALCdevice *device);
/**
* CalcDirectionCoeffs
*
@ -280,18 +439,6 @@ void aluInitEffectPanning(struct ALeffectslot *slot);
*/
void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
/**
* CalcXYZCoeffs
*
* Same as CalcDirectionCoeffs except the direction is specified as separate x,
* y, and z parameters instead of an array.
*/
inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
{
ALfloat dir[3] = { x, y, z };
CalcDirectionCoeffs(dir, spread, coeffs);
}
/**
* CalcAngleCoeffs
*
@ -299,37 +446,46 @@ inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALflo
* azimuth and elevation parameters are in radians, going right and up
* respectively.
*/
void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
{
ALfloat dir[3] = {
sinf(azimuth) * cosf(elevation),
sinf(elevation),
-cosf(azimuth) * cosf(elevation)
};
CalcDirectionCoeffs(dir, spread, coeffs);
}
/**
* ComputeAmbientGains
* CalcAnglePairwiseCoeffs
*
* Computes channel gains for ambient, omni-directional sounds.
* Calculates ambisonic coefficients based on azimuth and elevation. The
* azimuth and elevation parameters are in radians, going right and up
* respectively. This pairwise variant warps the result such that +30 azimuth
* is full right, and -30 azimuth is full left.
*/
#define ComputeAmbientGains(b, g, o) do { \
if((b).CoeffCount > 0) \
ComputeAmbientGainsMC((b).Ambi.Coeffs, (b).NumChannels, g, o); \
else \
ComputeAmbientGainsBF((b).Ambi.Map, (b).NumChannels, g, o); \
} while (0)
void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
/**
* ComputePanningGains
* ComputeDryPanGains
*
* Computes panning gains using the given channel decoder coefficients and the
* pre-calculated direction or angle coefficients.
*/
#define ComputePanningGains(b, c, g, o) do { \
if((b).CoeffCount > 0) \
ComputePanningGainsMC((b).Ambi.Coeffs, (b).NumChannels, (b).CoeffCount, c, g, o);\
else \
ComputePanningGainsBF((b).Ambi.Map, (b).NumChannels, c, g, o); \
} while (0)
void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
{
if(dry->CoeffCount > 0)
ComputePanningGainsMC(dry->Ambi.Coeffs, dry->NumChannels, dry->CoeffCount,
coeffs, ingain, gains);
else
ComputePanningGainsBF(dry->Ambi.Map, dry->NumChannels, coeffs, ingain, gains);
}
void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
/**
* ComputeFirstOrderGains
*
@ -337,24 +493,29 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, cons
* a 1x4 'slice' of a transform matrix for the input channel, used to scale and
* orient the sound samples.
*/
#define ComputeFirstOrderGains(b, m, g, o) do { \
if((b).CoeffCount > 0) \
ComputeFirstOrderGainsMC((b).Ambi.Coeffs, (b).NumChannels, m, g, o); \
else \
ComputeFirstOrderGainsBF((b).Ambi.Map, (b).NumChannels, m, g, o); \
} while (0)
void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
{
if(foa->CoeffCount > 0)
ComputeFirstOrderGainsMC(foa->Ambi.Coeffs, foa->NumChannels, mtx, ingain, gains);
else
ComputeFirstOrderGainsBF(foa->Ambi.Map, foa->NumChannels, mtx, ingain, gains);
}
ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo);
ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo);
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
/* Caller must lock the device. */
ALvoid aluHandleDisconnect(ALCdevice *device);
void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples);
/* Caller must lock the device, and the mixer must not be running. */
void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3);
void UpdateContextProps(ALCcontext *context);
extern MixerFunc MixSamples;
extern RowMixerFunc MixRowSamples;
extern ALfloat ConeScale;
extern ALfloat ZScale;
extern ALboolean OverrideReverbSpeedOfSound;
#ifdef __cplusplus
}

View file

@ -85,7 +85,7 @@ int bs2b_get_srate(struct bs2b *bs2b);
/* Clear buffer */
void bs2b_clear(struct bs2b *bs2b);
void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, unsigned int SamplesToDo);
void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, int SamplesToDo);
#ifdef __cplusplus
} /* extern "C" */

View file

@ -4,6 +4,12 @@
#include "AL/al.h"
#include "alBuffer.h"
void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align);
extern const ALshort muLawDecompressionTable[256];
extern const ALshort aLawDecompressionTable[256];
void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len,
ALsizei align);
void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len,
ALsizei align);
#endif /* SAMPLE_CVT_H */

View file

@ -27,99 +27,140 @@
#include "AL/alc.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alThunk.h"
#include "alError.h"
#include "alListener.h"
#include "alSource.h"
#include "fpu_modes.h"
#include "almalloc.h"
extern inline void LockEffectSlotsRead(ALCcontext *context);
extern inline void UnlockEffectSlotsRead(ALCcontext *context);
extern inline void LockEffectSlotsWrite(ALCcontext *context);
extern inline void UnlockEffectSlotsWrite(ALCcontext *context);
extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id);
extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id);
extern inline void LockEffectSlotList(ALCcontext *context);
extern inline void UnlockEffectSlotList(ALCcontext *context);
static void RemoveEffectSlotList(ALCcontext *Context, ALeffectslot *slot);
static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context);
static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context);
static UIntMap EffectStateFactoryMap;
static inline ALeffectStateFactory *getFactoryByType(ALenum type)
static const struct {
ALenum Type;
EffectStateFactory* (*GetFactory)(void);
} FactoryList[] = {
{ AL_EFFECT_NULL, NullStateFactory_getFactory },
{ AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory },
{ AL_EFFECT_REVERB, ReverbStateFactory_getFactory },
{ AL_EFFECT_CHORUS, ChorusStateFactory_getFactory },
{ AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory },
{ AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory },
{ AL_EFFECT_ECHO, EchoStateFactory_getFactory },
{ AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory },
{ AL_EFFECT_FLANGER, FlangerStateFactory_getFactory },
{ AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory },
{ AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory},
{ AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory },
{ AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory }
};
static inline EffectStateFactory *getFactoryByType(ALenum type)
{
ALeffectStateFactory* (*getFactory)(void) = LookupUIntMapKey(&EffectStateFactoryMap, type);
if(getFactory != NULL)
return getFactory();
size_t i;
for(i = 0;i < COUNTOF(FactoryList);i++)
{
if(FactoryList[i].Type == type)
return FactoryList[i].GetFactory();
}
return NULL;
}
static void ALeffectState_IncRef(ALeffectState *state);
static void ALeffectState_DecRef(ALeffectState *state);
static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
{
id--;
if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList)))
return NULL;
return VECTOR_ELEM(context->EffectSlotList, id);
}
static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
{
EffectSubList *sublist;
ALuint lidx = (id-1) >> 6;
ALsizei slidx = (id-1) & 0x3f;
if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList)))
return NULL;
sublist = &VECTOR_ELEM(device->EffectList, lidx);
if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
return NULL;
return sublist->Effects + slidx;
}
#define DO_UPDATEPROPS() do { \
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
UpdateEffectSlotProps(slot); \
UpdateEffectSlotProps(slot, context); \
else \
slot->NeedsUpdate = AL_TRUE; \
ATOMIC_FLAG_CLEAR(&slot->PropsClean, almemory_order_release); \
} while(0)
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCdevice *device;
ALCcontext *context;
ALeffectslot *first, *last;
ALsizei cur;
ALenum err;
context = GetContextRef();
if(!context) return;
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n);
if(n == 0) goto done;
first = last = NULL;
LockEffectSlotList(context);
device = context->Device;
if(device->AuxiliaryEffectSlotMax - VECTOR_SIZE(context->EffectSlotList) < (ALuint)n)
{
UnlockEffectSlotList(context);
SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Exceeding %u auxiliary effect slot limit",
device->AuxiliaryEffectSlotMax);
}
for(cur = 0;cur < n;cur++)
{
ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
err = AL_OUT_OF_MEMORY;
ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList);
ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList);
ALeffectslot *slot = NULL;
ALenum err = AL_OUT_OF_MEMORY;
for(;iter != end;iter++)
{
if(!*iter)
break;
}
if(iter == end)
{
VECTOR_PUSH_BACK(context->EffectSlotList, NULL);
iter = &VECTOR_BACK(context->EffectSlotList);
}
slot = al_calloc(16, sizeof(ALeffectslot));
if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
{
al_free(slot);
alDeleteAuxiliaryEffectSlots(cur, effectslots);
SET_ERROR_AND_GOTO(context, err, done);
}
err = NewThunkEntry(&slot->id);
if(err == AL_NO_ERROR)
err = InsertUIntMapEntry(&context->EffectSlotMap, slot->id, slot);
if(err != AL_NO_ERROR)
{
FreeThunkEntry(slot->id);
ALeffectState_DecRef(slot->Effect.State);
if(slot->Params.EffectState)
ALeffectState_DecRef(slot->Params.EffectState);
al_free(slot);
UnlockEffectSlotList(context);
alDeleteAuxiliaryEffectSlots(cur, effectslots);
SET_ERROR_AND_GOTO(context, err, done);
SETERR_GOTO(context, err, done, "Effect slot object allocation failed");
}
aluInitEffectPanning(slot);
if(!first) first = slot;
if(last) ATOMIC_STORE(&last->next, slot, almemory_order_relaxed);
last = slot;
slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1;
*iter = slot;
effectslots[cur] = slot->id;
}
if(last != NULL)
{
ALeffectslot *root = ATOMIC_LOAD(&context->ActiveAuxSlotList);
do {
ATOMIC_STORE(&last->next, root, almemory_order_relaxed);
} while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALeffectslot*, &context->ActiveAuxSlotList,
&root, first));
}
AddActiveEffectSlots(effectslots, n, context);
UnlockEffectSlotList(context);
done:
ALCcontext_DecRef(context);
@ -134,25 +175,29 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *
context = GetContextRef();
if(!context) return;
LockEffectSlotsWrite(context);
LockEffectSlotList(context);
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n);
if(n == 0) goto done;
for(i = 0;i < n;i++)
{
if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u",
effectslots[i]);
if(ReadRef(&slot->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Deleting in-use effect slot %u",
effectslots[i]);
}
// All effectslots are valid
RemoveActiveEffectSlots(effectslots, n, context);
for(i = 0;i < n;i++)
{
if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
continue;
FreeThunkEntry(slot->id);
VECTOR_ELEM(context->EffectSlotList, effectslots[i]-1) = NULL;
RemoveEffectSlotList(context, slot);
DeinitEffectSlot(slot);
memset(slot, 0, sizeof(*slot));
@ -160,7 +205,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *
}
done:
UnlockEffectSlotsWrite(context);
UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@ -172,9 +217,9 @@ AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
context = GetContextRef();
if(!context) return AL_FALSE;
LockEffectSlotsRead(context);
LockEffectSlotList(context);
ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
UnlockEffectSlotsRead(context);
UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
@ -192,43 +237,45 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
LockEffectSlotsRead(context);
almtx_lock(&context->PropLock);
LockEffectSlotList(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
switch(param)
{
case AL_EFFECTSLOT_EFFECT:
device = context->Device;
LockEffectsRead(device);
LockEffectList(device);
effect = (value ? LookupEffect(device, value) : NULL);
if(!(value == 0 || effect != NULL))
{
UnlockEffectsRead(device);
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
UnlockEffectList(device);
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid effect ID %u", value);
}
err = InitializeEffect(device, slot, effect);
UnlockEffectsRead(device);
err = InitializeEffect(context, slot, effect);
UnlockEffectList(device);
if(err != AL_NO_ERROR)
SET_ERROR_AND_GOTO(context, err, done);
SETERR_GOTO(context, err, done, "Effect initialization failed");
break;
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
if(!(value == AL_TRUE || value == AL_FALSE))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
SETERR_GOTO(context, AL_INVALID_VALUE, done,
"Effect slot auxiliary send auto out of range");
slot->AuxSendAuto = value;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot integer property 0x%04x",
param);
}
DO_UPDATEPROPS();
done:
UnlockEffectSlotsRead(context);
WriteUnlock(&context->PropLock);
UnlockEffectSlotList(context);
almtx_unlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -247,17 +294,18 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
LockEffectSlotList(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
param);
}
done:
UnlockEffectSlotsRead(context);
UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@ -269,26 +317,27 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
LockEffectSlotsRead(context);
almtx_lock(&context->PropLock);
LockEffectSlotList(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
switch(param)
{
case AL_EFFECTSLOT_GAIN:
if(!(value >= 0.0f && value <= 1.0f))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Effect slot gain out of range");
slot->Gain = value;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot float property 0x%04x",
param);
}
DO_UPDATEPROPS();
done:
UnlockEffectSlotsRead(context);
WriteUnlock(&context->PropLock);
UnlockEffectSlotList(context);
almtx_unlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -306,17 +355,18 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
LockEffectSlotList(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
param);
}
done:
UnlockEffectSlotsRead(context);
UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@ -328,9 +378,9 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
LockEffectSlotList(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
switch(param)
{
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
@ -338,11 +388,11 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param);
}
done:
UnlockEffectSlotsRead(context);
UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@ -361,17 +411,18 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
LockEffectSlotList(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
param);
}
done:
UnlockEffectSlotsRead(context);
UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@ -383,9 +434,9 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
LockEffectSlotList(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
switch(param)
{
case AL_EFFECTSLOT_GAIN:
@ -393,11 +444,11 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param);
}
done:
UnlockEffectSlotsRead(context);
UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@ -415,76 +466,32 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
LockEffectSlotList(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
param);
}
done:
UnlockEffectSlotsRead(context);
UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
static void RemoveEffectSlotList(ALCcontext *context, ALeffectslot *slot)
{
ALCdevice *device = context->Device;
ALeffectslot *root, *next;
root = slot;
next = ATOMIC_LOAD(&slot->next);
if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALeffectslot*, &context->ActiveAuxSlotList, &root, next))
{
ALeffectslot *cur;
do {
cur = root;
root = slot;
} while(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALeffectslot*, &cur->next, &root, next));
}
/* Wait for any mix that may be using these effect slots to finish. */
while((ReadRef(&device->MixCount)&1) != 0)
althrd_yield();
}
void InitEffectFactoryMap(void)
{
InitUIntMap(&EffectStateFactoryMap, ~0);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_NULL, ALnullStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_REVERB, ALreverbStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_CHORUS, ALchorusStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_COMPRESSOR, ALcompressorStateFactory_getFactory);
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);
}
void DeinitEffectFactoryMap(void)
{
ResetUIntMap(&EffectStateFactoryMap);
}
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
{
ALCdevice *Device = Context->Device;
ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
struct ALeffectslotProps *props;
ALeffectState *State;
if(newtype != EffectSlot->Effect.Type)
{
ALeffectStateFactory *factory;
FPUCtl oldMode;
EffectStateFactory *factory;
factory = getFactoryByType(newtype);
if(!factory)
@ -492,22 +499,22 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
ERR("Failed to find factory for effect type 0x%04x\n", newtype);
return AL_INVALID_ENUM;
}
State = V0(factory,create)();
State = EffectStateFactory_create(factory);
if(!State) return AL_OUT_OF_MEMORY;
SetMixerFPUMode(&oldMode);
START_MIXER_MODE();
almtx_lock(&Device->BackendLock);
State->OutBuffer = Device->Dry.Buffer;
State->OutChannels = Device->Dry.NumChannels;
if(V(State,deviceUpdate)(Device) == AL_FALSE)
{
almtx_unlock(&Device->BackendLock);
RestoreFPUMode(&oldMode);
LEAVE_MIXER_MODE();
ALeffectState_DecRef(State);
return AL_OUT_OF_MEMORY;
}
almtx_unlock(&Device->BackendLock);
RestoreFPUMode(&oldMode);
END_MIXER_MODE();
if(!effect)
{
@ -527,11 +534,12 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
EffectSlot->Effect.Props = effect->Props;
/* Remove state references from old effect slot property updates. */
props = ATOMIC_LOAD(&EffectSlot->FreeList);
props = ATOMIC_LOAD_SEQ(&Context->FreeEffectslotProps);
while(props)
{
State = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed);
if(State) ALeffectState_DecRef(State);
if(props->State)
ALeffectState_DecRef(props->State);
props->State = NULL;
props = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
}
@ -546,7 +554,7 @@ static void ALeffectState_IncRef(ALeffectState *state)
TRACEREF("%p increasing refcount to %u\n", state, ref);
}
static void ALeffectState_DecRef(ALeffectState *state)
void ALeffectState_DecRef(ALeffectState *state)
{
uint ref;
ref = DecrementRef(&state->Ref);
@ -568,23 +576,110 @@ void ALeffectState_Destruct(ALeffectState *UNUSED(state))
}
static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context)
{
struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots,
almemory_order_acquire);
struct ALeffectslotArray *newarray = NULL;
ALsizei newcount = curarray->count + count;
ALCdevice *device = context->Device;
ALsizei i, j;
/* Insert the new effect slots into the head of the array, followed by the
* existing ones.
*/
newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount));
newarray->count = newcount;
for(i = 0;i < count;i++)
newarray->slot[i] = LookupEffectSlot(context, slotids[i]);
for(j = 0;i < newcount;)
newarray->slot[i++] = curarray->slot[j++];
/* Remove any duplicates (first instance of each will be kept). */
for(i = 1;i < newcount;i++)
{
for(j = i;j != 0;)
{
if(UNLIKELY(newarray->slot[i] == newarray->slot[--j]))
{
newcount--;
for(j = i;j < newcount;j++)
newarray->slot[j] = newarray->slot[j+1];
i--;
break;
}
}
}
/* Reallocate newarray if the new size ended up smaller from duplicate
* removal.
*/
if(UNLIKELY(newcount < newarray->count))
{
struct ALeffectslotArray *tmpnewarray = al_calloc(DEF_ALIGN,
FAM_SIZE(struct ALeffectslotArray, slot, newcount));
memcpy(tmpnewarray, newarray, FAM_SIZE(struct ALeffectslotArray, slot, newcount));
al_free(newarray);
newarray = tmpnewarray;
newarray->count = newcount;
}
curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel);
while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
althrd_yield();
al_free(curarray);
}
static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context)
{
struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots,
almemory_order_acquire);
struct ALeffectslotArray *newarray = NULL;
ALCdevice *device = context->Device;
ALsizei i, j;
/* Don't shrink the allocated array size since we don't know how many (if
* any) of the effect slots to remove are in the array.
*/
newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, curarray->count));
newarray->count = 0;
for(i = 0;i < curarray->count;i++)
{
/* Insert this slot into the new array only if it's not one to remove. */
ALeffectslot *slot = curarray->slot[i];
for(j = count;j != 0;)
{
if(slot->id == slotids[--j])
goto skip_ins;
}
newarray->slot[newarray->count++] = slot;
skip_ins: ;
}
/* TODO: Could reallocate newarray now that we know it's needed size. */
curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel);
while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
althrd_yield();
al_free(curarray);
}
ALenum InitEffectSlot(ALeffectslot *slot)
{
ALeffectStateFactory *factory;
EffectStateFactory *factory;
slot->Effect.Type = AL_EFFECT_NULL;
factory = getFactoryByType(AL_EFFECT_NULL);
if(!(slot->Effect.State=V0(factory,create)()))
return AL_OUT_OF_MEMORY;
slot->Effect.State = EffectStateFactory_create(factory);
if(!slot->Effect.State) return AL_OUT_OF_MEMORY;
slot->NeedsUpdate = AL_FALSE;
slot->Gain = 1.0;
slot->AuxSendAuto = AL_TRUE;
ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_relaxed);
InitRef(&slot->ref, 0);
ATOMIC_INIT(&slot->Update, NULL);
ATOMIC_INIT(&slot->FreeList, NULL);
slot->Params.Gain = 1.0f;
slot->Params.AuxSendAuto = AL_TRUE;
@ -592,52 +687,38 @@ ALenum InitEffectSlot(ALeffectslot *slot)
slot->Params.EffectState = slot->Effect.State;
slot->Params.RoomRolloff = 0.0f;
slot->Params.DecayTime = 0.0f;
slot->Params.DecayLFRatio = 0.0f;
slot->Params.DecayHFRatio = 0.0f;
slot->Params.DecayHFLimit = AL_FALSE;
slot->Params.AirAbsorptionGainHF = 1.0f;
ATOMIC_INIT(&slot->next, NULL);
return AL_NO_ERROR;
}
void DeinitEffectSlot(ALeffectslot *slot)
{
struct ALeffectslotProps *props;
ALeffectState *state;
size_t count = 0;
props = ATOMIC_LOAD(&slot->Update);
props = ATOMIC_LOAD_SEQ(&slot->Update);
if(props)
{
state = ATOMIC_LOAD(&props->State, almemory_order_relaxed);
if(state) ALeffectState_DecRef(state);
if(props->State) ALeffectState_DecRef(props->State);
TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
al_free(props);
}
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
while(props)
{
struct ALeffectslotProps *next;
state = ATOMIC_LOAD(&props->State, almemory_order_relaxed);
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
if(state) ALeffectState_DecRef(state);
al_free(props);
props = next;
++count;
}
TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
ALeffectState_DecRef(slot->Effect.State);
if(slot->Params.EffectState)
ALeffectState_DecRef(slot->Params.EffectState);
}
void UpdateEffectSlotProps(ALeffectslot *slot)
void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
{
struct ALeffectslotProps *props;
ALeffectState *oldstate;
/* Get an unused property container, or allocate a new one as needed. */
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
props = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed);
if(!props)
props = al_calloc(16, sizeof(*props));
else
@ -645,37 +726,31 @@ void UpdateEffectSlotProps(ALeffectslot *slot)
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);
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeEffectslotProps, &props, next,
almemory_order_seq_cst, almemory_order_acquire) == 0);
}
/* Copy in current property values. */
ATOMIC_STORE(&props->Gain, slot->Gain, almemory_order_relaxed);
ATOMIC_STORE(&props->AuxSendAuto, slot->AuxSendAuto, almemory_order_relaxed);
props->Gain = slot->Gain;
props->AuxSendAuto = slot->AuxSendAuto;
ATOMIC_STORE(&props->Type, slot->Effect.Type, almemory_order_relaxed);
props->Type = slot->Effect.Type;
props->Props = slot->Effect.Props;
/* Swap out any stale effect state object there may be in the container, to
* delete it.
*/
ALeffectState_IncRef(slot->Effect.State);
oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State,
almemory_order_relaxed);
oldstate = props->State;
props->State = slot->Effect.State;
/* Set the new container for updating internal parameters. */
props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, props,
almemory_order_acq_rel);
props = ATOMIC_EXCHANGE_PTR(&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);
ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props);
}
if(oldstate)
@ -684,32 +759,38 @@ void UpdateEffectSlotProps(ALeffectslot *slot)
void UpdateAllEffectSlotProps(ALCcontext *context)
{
ALeffectslot *slot;
struct ALeffectslotArray *auxslots;
ALsizei i;
LockEffectSlotsRead(context);
slot = ATOMIC_LOAD(&context->ActiveAuxSlotList);
while(slot)
LockEffectSlotList(context);
auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire);
for(i = 0;i < auxslots->count;i++)
{
if(slot->NeedsUpdate)
UpdateEffectSlotProps(slot);
slot->NeedsUpdate = AL_FALSE;
slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed);
ALeffectslot *slot = auxslots->slot[i];
if(!ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel))
UpdateEffectSlotProps(slot, context);
}
UnlockEffectSlotsRead(context);
UnlockEffectSlotList(context);
}
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context)
{
ALsizei pos;
for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList);
ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList);
size_t leftover = 0;
for(;iter != end;iter++)
{
ALeffectslot *temp = Context->EffectSlotMap.values[pos];
Context->EffectSlotMap.values[pos] = NULL;
ALeffectslot *slot = *iter;
if(!slot) continue;
*iter = NULL;
DeinitEffectSlot(temp);
DeinitEffectSlot(slot);
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALeffectslot));
al_free(temp);
memset(slot, 0, sizeof(*slot));
al_free(slot);
++leftover;
}
if(leftover > 0)
WARN("(%p) Deleted "SZFMT" AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s");
}

File diff suppressed because it is too large Load diff

View file

@ -28,26 +28,51 @@
#include "AL/alc.h"
#include "alMain.h"
#include "alEffect.h"
#include "alThunk.h"
#include "alError.h"
ALboolean DisabledEffects[MAX_EFFECTS];
extern inline void LockEffectsRead(ALCdevice *device);
extern inline void UnlockEffectsRead(ALCdevice *device);
extern inline void LockEffectsWrite(ALCdevice *device);
extern inline void UnlockEffectsWrite(ALCdevice *device);
extern inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id);
extern inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id);
extern inline void LockEffectList(ALCdevice *device);
extern inline void UnlockEffectList(ALCdevice *device);
extern inline ALboolean IsReverbEffect(ALenum type);
const struct EffectList EffectList[EFFECTLIST_SIZE] = {
{ "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB },
{ "reverb", REVERB_EFFECT, AL_EFFECT_REVERB },
{ "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS },
{ "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR },
{ "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION },
{ "echo", ECHO_EFFECT, AL_EFFECT_ECHO },
{ "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER },
{ "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER },
{ "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR },
{ "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER },
{ "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
{ "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE },
};
ALboolean DisabledEffects[MAX_EFFECTS];
static ALeffect *AllocEffect(ALCcontext *context);
static void FreeEffect(ALCdevice *device, ALeffect *effect);
static void InitEffectParams(ALeffect *effect, ALenum type);
static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
{
EffectSubList *sublist;
ALuint lidx = (id-1) >> 6;
ALsizei slidx = (id-1) & 0x3f;
if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList)))
return NULL;
sublist = &VECTOR_ELEM(device->EffectList, lidx);
if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
return NULL;
return sublist->Effects + slidx;
}
AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
{
ALCdevice *device;
ALCcontext *context;
ALsizei cur;
@ -55,37 +80,18 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
if(!context) return;
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
device = context->Device;
for(cur = 0;cur < n;cur++)
alSetError(context, AL_INVALID_VALUE, "Generating %d effects", n);
else for(cur = 0;cur < n;cur++)
{
ALeffect *effect = al_calloc(16, sizeof(ALeffect));
ALenum err = AL_OUT_OF_MEMORY;
if(!effect || (err=InitEffect(effect)) != AL_NO_ERROR)
ALeffect *effect = AllocEffect(context);
if(!effect)
{
al_free(effect);
alDeleteEffects(cur, effects);
SET_ERROR_AND_GOTO(context, err, done);
break;
}
err = NewThunkEntry(&effect->id);
if(err == AL_NO_ERROR)
err = InsertUIntMapEntry(&device->EffectMap, effect->id, effect);
if(err != AL_NO_ERROR)
{
FreeThunkEntry(effect->id);
memset(effect, 0, sizeof(ALeffect));
al_free(effect);
alDeleteEffects(cur, effects);
SET_ERROR_AND_GOTO(context, err, done);
}
effects[cur] = effect->id;
}
done:
ALCcontext_DecRef(context);
}
@ -100,26 +106,22 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
if(!context) return;
device = context->Device;
LockEffectsWrite(device);
LockEffectList(device);
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effects", n);
for(i = 0;i < n;i++)
{
if(effects[i] && LookupEffect(device, effects[i]) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect ID %u", effects[i]);
}
for(i = 0;i < n;i++)
{
if((effect=RemoveEffect(device, effects[i])) == NULL)
continue;
FreeThunkEntry(effect->id);
memset(effect, 0, sizeof(*effect));
al_free(effect);
if((effect=LookupEffect(device, effects[i])) != NULL)
FreeEffect(device, effect);
}
done:
UnlockEffectsWrite(device);
UnlockEffectList(device);
ALCcontext_DecRef(context);
}
@ -131,10 +133,10 @@ AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
Context = GetContextRef();
if(!Context) return AL_FALSE;
LockEffectsRead(Context->Device);
LockEffectList(Context->Device);
result = ((!effect || LookupEffect(Context->Device, effect)) ?
AL_TRUE : AL_FALSE);
UnlockEffectsRead(Context->Device);
UnlockEffectList(Context->Device);
ALCcontext_DecRef(Context);
@ -151,16 +153,16 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
if(!Context) return;
Device = Context->Device;
LockEffectsWrite(Device);
LockEffectList(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
else
{
if(param == AL_EFFECT_TYPE)
{
ALboolean isOk = (value == AL_EFFECT_NULL);
ALint i;
for(i = 0;!isOk && EffectList[i].val;i++)
for(i = 0;!isOk && i < EFFECTLIST_SIZE;i++)
{
if(value == EffectList[i].val &&
!DisabledEffects[EffectList[i].type])
@ -170,15 +172,15 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
if(isOk)
InitEffectParams(ALEffect, value);
else
alSetError(Context, AL_INVALID_VALUE);
alSetError(Context, AL_INVALID_VALUE, "Effect type 0x%04x not supported", value);
}
else
{
/* Call the appropriate handler */
V(ALEffect,setParami)(Context, param, value);
ALeffect_setParami(ALEffect, Context, param, value);
}
}
UnlockEffectsWrite(Device);
UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@ -200,15 +202,15 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v
if(!Context) return;
Device = Context->Device;
LockEffectsWrite(Device);
LockEffectList(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
else
{
/* Call the appropriate handler */
V(ALEffect,setParamiv)(Context, param, values);
ALeffect_setParamiv(ALEffect, Context, param, values);
}
UnlockEffectsWrite(Device);
UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@ -223,15 +225,15 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
if(!Context) return;
Device = Context->Device;
LockEffectsWrite(Device);
LockEffectList(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
else
{
/* Call the appropriate handler */
V(ALEffect,setParamf)(Context, param, value);
ALeffect_setParamf(ALEffect, Context, param, value);
}
UnlockEffectsWrite(Device);
UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@ -246,15 +248,15 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat
if(!Context) return;
Device = Context->Device;
LockEffectsWrite(Device);
LockEffectList(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
else
{
/* Call the appropriate handler */
V(ALEffect,setParamfv)(Context, param, values);
ALeffect_setParamfv(ALEffect, Context, param, values);
}
UnlockEffectsWrite(Device);
UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@ -269,9 +271,9 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value
if(!Context) return;
Device = Context->Device;
LockEffectsRead(Device);
LockEffectList(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
else
{
if(param == AL_EFFECT_TYPE)
@ -279,10 +281,10 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value
else
{
/* Call the appropriate handler */
V(ALEffect,getParami)(Context, param, value);
ALeffect_getParami(ALEffect, Context, param, value);
}
}
UnlockEffectsRead(Device);
UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@ -304,15 +306,15 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu
if(!Context) return;
Device = Context->Device;
LockEffectsRead(Device);
LockEffectList(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
else
{
/* Call the appropriate handler */
V(ALEffect,getParamiv)(Context, param, values);
ALeffect_getParamiv(ALEffect, Context, param, values);
}
UnlockEffectsRead(Device);
UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@ -327,15 +329,15 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val
if(!Context) return;
Device = Context->Device;
LockEffectsRead(Device);
LockEffectList(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
else
{
/* Call the appropriate handler */
V(ALEffect,getParamf)(Context, param, value);
ALeffect_getParamf(ALEffect, Context, param, value);
}
UnlockEffectsRead(Device);
UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@ -350,39 +352,120 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va
if(!Context) return;
Device = Context->Device;
LockEffectsRead(Device);
LockEffectList(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
else
{
/* Call the appropriate handler */
V(ALEffect,getParamfv)(Context, param, values);
ALeffect_getParamfv(ALEffect, Context, param, values);
}
UnlockEffectsRead(Device);
UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
ALenum InitEffect(ALeffect *effect)
void InitEffect(ALeffect *effect)
{
InitEffectParams(effect, AL_EFFECT_NULL);
return AL_NO_ERROR;
}
ALvoid ReleaseALEffects(ALCdevice *device)
static ALeffect *AllocEffect(ALCcontext *context)
{
ALsizei i;
for(i = 0;i < device->EffectMap.size;i++)
{
ALeffect *temp = device->EffectMap.values[i];
device->EffectMap.values[i] = NULL;
ALCdevice *device = context->Device;
EffectSubList *sublist, *subend;
ALeffect *effect = NULL;
ALsizei lidx = 0;
ALsizei slidx;
// Release effect structure
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALeffect));
al_free(temp);
almtx_lock(&device->EffectLock);
sublist = VECTOR_BEGIN(device->EffectList);
subend = VECTOR_END(device->EffectList);
for(;sublist != subend;++sublist)
{
if(sublist->FreeMask)
{
slidx = CTZ64(sublist->FreeMask);
effect = sublist->Effects + slidx;
break;
}
++lidx;
}
if(UNLIKELY(!effect))
{
const EffectSubList empty_sublist = { 0, NULL };
/* Don't allocate so many list entries that the 32-bit ID could
* overflow...
*/
if(UNLIKELY(VECTOR_SIZE(device->EffectList) >= 1<<25))
{
almtx_unlock(&device->EffectLock);
alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated");
return NULL;
}
lidx = (ALsizei)VECTOR_SIZE(device->EffectList);
VECTOR_PUSH_BACK(device->EffectList, empty_sublist);
sublist = &VECTOR_BACK(device->EffectList);
sublist->FreeMask = ~U64(0);
sublist->Effects = al_calloc(16, sizeof(ALeffect)*64);
if(UNLIKELY(!sublist->Effects))
{
VECTOR_POP_BACK(device->EffectList);
almtx_unlock(&device->EffectLock);
alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch");
return NULL;
}
slidx = 0;
effect = sublist->Effects + slidx;
}
memset(effect, 0, sizeof(*effect));
InitEffectParams(effect, AL_EFFECT_NULL);
/* Add 1 to avoid effect ID 0. */
effect->id = ((lidx<<6) | slidx) + 1;
sublist->FreeMask &= ~(U64(1)<<slidx);
almtx_unlock(&device->EffectLock);
return effect;
}
static void FreeEffect(ALCdevice *device, ALeffect *effect)
{
ALuint id = effect->id - 1;
ALsizei lidx = id >> 6;
ALsizei slidx = id & 0x3f;
memset(effect, 0, sizeof(*effect));
VECTOR_ELEM(device->EffectList, lidx).FreeMask |= U64(1) << slidx;
}
void ReleaseALEffects(ALCdevice *device)
{
EffectSubList *sublist = VECTOR_BEGIN(device->EffectList);
EffectSubList *subend = VECTOR_END(device->EffectList);
size_t leftover = 0;
for(;sublist != subend;++sublist)
{
ALuint64 usemask = ~sublist->FreeMask;
while(usemask)
{
ALsizei idx = CTZ64(usemask);
ALeffect *effect = sublist->Effects + idx;
memset(effect, 0, sizeof(*effect));
++leftover;
usemask &= ~(U64(1) << idx);
}
sublist->FreeMask = ~usemask;
}
if(leftover > 0)
WARN("(%p) Deleted "SZFMT" Effect%s\n", device, leftover, (leftover==1)?"":"s");
}
@ -418,7 +501,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
effect->Props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
effect->Props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
effect->Props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
SET_VTABLE1(ALeaxreverb, effect);
effect->vtab = &ALeaxreverb_vtable;
break;
case AL_EFFECT_REVERB:
effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY;
@ -448,7 +531,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
effect->Props.Reverb.LFReference = 250.0f;
effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
SET_VTABLE1(ALreverb, effect);
effect->vtab = &ALreverb_vtable;
break;
case AL_EFFECT_CHORUS:
effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM;
@ -457,11 +540,11 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
effect->Props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH;
effect->Props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
effect->Props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY;
SET_VTABLE1(ALchorus, effect);
effect->vtab = &ALchorus_vtable;
break;
case AL_EFFECT_COMPRESSOR:
effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF;
SET_VTABLE1(ALcompressor, effect);
effect->vtab = &ALcompressor_vtable;
break;
case AL_EFFECT_DISTORTION:
effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE;
@ -469,7 +552,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
effect->Props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
effect->Props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
effect->Props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
SET_VTABLE1(ALdistortion, effect);
effect->vtab = &ALdistortion_vtable;
break;
case AL_EFFECT_ECHO:
effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY;
@ -477,7 +560,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
effect->Props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
effect->Props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
effect->Props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
SET_VTABLE1(ALecho, effect);
effect->vtab = &ALecho_vtable;
break;
case AL_EFFECT_EQUALIZER:
effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF;
@ -490,30 +573,35 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
effect->Props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH;
effect->Props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF;
effect->Props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN;
SET_VTABLE1(ALequalizer, effect);
effect->vtab = &ALequalizer_vtable;
break;
case AL_EFFECT_FLANGER:
effect->Props.Flanger.Waveform = AL_FLANGER_DEFAULT_WAVEFORM;
effect->Props.Flanger.Phase = AL_FLANGER_DEFAULT_PHASE;
effect->Props.Flanger.Rate = AL_FLANGER_DEFAULT_RATE;
effect->Props.Flanger.Depth = AL_FLANGER_DEFAULT_DEPTH;
effect->Props.Flanger.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
effect->Props.Flanger.Delay = AL_FLANGER_DEFAULT_DELAY;
SET_VTABLE1(ALflanger, effect);
effect->Props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM;
effect->Props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE;
effect->Props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE;
effect->Props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH;
effect->Props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY;
effect->vtab = &ALflanger_vtable;
break;
case AL_EFFECT_RING_MODULATOR:
effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
effect->Props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM;
SET_VTABLE1(ALmodulator, effect);
effect->vtab = &ALmodulator_vtable;
break;
case AL_EFFECT_PITCH_SHIFTER:
effect->Props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE;
effect->Props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE;
effect->vtab = &ALpshifter_vtable;
break;
case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT:
case AL_EFFECT_DEDICATED_DIALOGUE:
effect->Props.Dedicated.Gain = 1.0f;
SET_VTABLE1(ALdedicated, effect);
effect->vtab = &ALdedicated_vtable;
break;
default:
SET_VTABLE1(ALnull, effect);
effect->vtab = &ALnull_vtable;
break;
}
effect->type = type;
@ -656,7 +744,7 @@ static const struct {
};
#undef DECL
ALvoid LoadReverbPreset(const char *name, ALeffect *effect)
void LoadReverbPreset(const char *name, ALeffect *effect)
{
size_t i;
@ -667,9 +755,9 @@ ALvoid LoadReverbPreset(const char *name, ALeffect *effect)
return;
}
if(!DisabledEffects[EAXREVERB])
if(!DisabledEffects[EAXREVERB_EFFECT])
InitEffectParams(effect, AL_EFFECT_EAXREVERB);
else if(!DisabledEffects[REVERB])
else if(!DisabledEffects[REVERB_EFFECT])
InitEffectParams(effect, AL_EFFECT_REVERB);
else
InitEffectParams(effect, AL_EFFECT_NULL);

View file

@ -21,6 +21,7 @@
#include "config.h"
#include <signal.h>
#include <stdarg.h>
#ifdef HAVE_WINDOWS_H
#define WIN32_LEAN_AND_MEAN
@ -33,9 +34,32 @@
ALboolean TrapALError = AL_FALSE;
ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...)
{
ALenum curerr = AL_NO_ERROR;
char message[1024] = { 0 };
va_list args;
int msglen;
va_start(args, msg);
msglen = vsnprintf(message, sizeof(message), msg, args);
va_end(args);
if(msglen < 0 || (size_t)msglen >= sizeof(message))
{
message[sizeof(message)-1] = 0;
msglen = (int)strlen(message);
}
if(msglen > 0)
msg = message;
else
{
msg = "<internal error constructing message>";
msglen = (int)strlen(msg);
}
WARN("Error generated on context %p, code 0x%04x, \"%s\"\n",
context, errorCode, message);
if(TrapALError)
{
#ifdef _WIN32
@ -46,17 +70,30 @@ ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
raise(SIGTRAP);
#endif
}
ATOMIC_COMPARE_EXCHANGE_STRONG(ALenum, &Context->LastError, &curerr, errorCode);
ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&context->LastError, &curerr, errorCode);
if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Error))
{
ALbitfieldSOFT enabledevts;
almtx_lock(&context->EventCbLock);
enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed);
if((enabledevts&EventType_Error) && context->EventCb)
(*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg,
context->EventParam);
almtx_unlock(&context->EventCbLock);
}
}
AL_API ALenum AL_APIENTRY alGetError(void)
{
ALCcontext *Context;
ALCcontext *context;
ALenum errorCode;
Context = GetContextRef();
if(!Context)
context = GetContextRef();
if(!context)
{
const ALenum deferror = AL_INVALID_OPERATION;
WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror);
if(TrapALError)
{
#ifdef _WIN32
@ -66,12 +103,11 @@ AL_API ALenum AL_APIENTRY alGetError(void)
raise(SIGTRAP);
#endif
}
return AL_INVALID_OPERATION;
return deferror;
}
errorCode = ATOMIC_EXCHANGE(ALenum, &Context->LastError, AL_NO_ERROR);
ALCcontext_DecRef(Context);
errorCode = ATOMIC_EXCHANGE_SEQ(&context->LastError, AL_NO_ERROR);
ALCcontext_DecRef(context);
return errorCode;
}

View file

@ -35,22 +35,6 @@
#include "AL/alc.h"
const struct EffectList EffectList[] = {
{ "eaxreverb", EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB },
{ "reverb", REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB },
{ "chorus", CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS },
{ "compressor", COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR },
{ "distortion", DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION },
{ "echo", ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO },
{ "equalizer", EQUALIZER, "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER },
{ "flanger", FLANGER, "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER },
{ "modulator", MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR },
{ "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
{ "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE },
{ NULL, 0, NULL, (ALenum)0 }
};
AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName)
{
ALboolean ret = AL_FALSE;
@ -61,8 +45,8 @@ AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName)
context = GetContextRef();
if(!context) return AL_FALSE;
if(!(extName))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if(!extName)
SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer");
len = strlen(extName);
ptr = context->ExtensionList;

View file

@ -25,65 +25,53 @@
#include "alMain.h"
#include "alu.h"
#include "alFilter.h"
#include "alThunk.h"
#include "alError.h"
extern inline void LockFiltersRead(ALCdevice *device);
extern inline void UnlockFiltersRead(ALCdevice *device);
extern inline void LockFiltersWrite(ALCdevice *device);
extern inline void UnlockFiltersWrite(ALCdevice *device);
extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id);
extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id);
extern inline void ALfilterState_clear(ALfilterState *filter);
extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALuint numsamples);
extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope);
extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth);
extern inline void LockFilterList(ALCdevice *device);
extern inline void UnlockFilterList(ALCdevice *device);
static ALfilter *AllocFilter(ALCcontext *context);
static void FreeFilter(ALCdevice *device, ALfilter *filter);
static void InitFilterParams(ALfilter *filter, ALenum type);
static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id)
{
FilterSubList *sublist;
ALuint lidx = (id-1) >> 6;
ALsizei slidx = (id-1) & 0x3f;
if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList)))
return NULL;
sublist = &VECTOR_ELEM(device->FilterList, lidx);
if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
return NULL;
return sublist->Filters + slidx;
}
AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
{
ALCdevice *device;
ALCcontext *context;
ALsizei cur = 0;
ALenum err;
context = GetContextRef();
if(!context) return;
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
device = context->Device;
for(cur = 0;cur < n;cur++)
alSetError(context, AL_INVALID_VALUE, "Generating %d filters", n);
else for(cur = 0;cur < n;cur++)
{
ALfilter *filter = al_calloc(16, sizeof(ALfilter));
ALfilter *filter = AllocFilter(context);
if(!filter)
{
alDeleteFilters(cur, filters);
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
}
InitFilterParams(filter, AL_FILTER_NULL);
err = NewThunkEntry(&filter->id);
if(err == AL_NO_ERROR)
err = InsertUIntMapEntry(&device->FilterMap, filter->id, filter);
if(err != AL_NO_ERROR)
{
FreeThunkEntry(filter->id);
memset(filter, 0, sizeof(ALfilter));
al_free(filter);
alDeleteFilters(cur, filters);
SET_ERROR_AND_GOTO(context, err, done);
break;
}
filters[cur] = filter->id;
}
done:
ALCcontext_DecRef(context);
}
@ -98,26 +86,22 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
if(!context) return;
device = context->Device;
LockFiltersWrite(device);
LockFilterList(device);
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d filters", n);
for(i = 0;i < n;i++)
{
if(filters[i] && LookupFilter(device, filters[i]) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid filter ID %u", filters[i]);
}
for(i = 0;i < n;i++)
{
if((filter=RemoveFilter(device, filters[i])) == NULL)
continue;
FreeThunkEntry(filter->id);
memset(filter, 0, sizeof(*filter));
al_free(filter);
if((filter=LookupFilter(device, filters[i])) != NULL)
FreeFilter(device, filter);
}
done:
UnlockFiltersWrite(device);
UnlockFilterList(device);
ALCcontext_DecRef(context);
}
@ -129,10 +113,10 @@ AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
Context = GetContextRef();
if(!Context) return AL_FALSE;
LockFiltersRead(Context->Device);
LockFilterList(Context->Device);
result = ((!filter || LookupFilter(Context->Device, filter)) ?
AL_TRUE : AL_FALSE);
UnlockFiltersRead(Context->Device);
UnlockFilterList(Context->Device);
ALCcontext_DecRef(Context);
@ -149,9 +133,9 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
if(!Context) return;
Device = Context->Device;
LockFiltersWrite(Device);
LockFilterList(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
else
{
if(param == AL_FILTER_TYPE)
@ -160,15 +144,15 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS)
InitFilterParams(ALFilter, value);
else
alSetError(Context, AL_INVALID_VALUE);
alSetError(Context, AL_INVALID_VALUE, "Invalid filter type 0x%04x", value);
}
else
{
/* Call the appropriate handler */
ALfilter_SetParami(ALFilter, Context, param, value);
ALfilter_setParami(ALFilter, Context, param, value);
}
}
UnlockFiltersWrite(Device);
UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@ -190,15 +174,15 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v
if(!Context) return;
Device = Context->Device;
LockFiltersWrite(Device);
LockFilterList(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
else
{
/* Call the appropriate handler */
ALfilter_SetParamiv(ALFilter, Context, param, values);
ALfilter_setParamiv(ALFilter, Context, param, values);
}
UnlockFiltersWrite(Device);
UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@ -213,15 +197,15 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
if(!Context) return;
Device = Context->Device;
LockFiltersWrite(Device);
LockFilterList(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
else
{
/* Call the appropriate handler */
ALfilter_SetParamf(ALFilter, Context, param, value);
ALfilter_setParamf(ALFilter, Context, param, value);
}
UnlockFiltersWrite(Device);
UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@ -236,15 +220,15 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat
if(!Context) return;
Device = Context->Device;
LockFiltersWrite(Device);
LockFilterList(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
else
{
/* Call the appropriate handler */
ALfilter_SetParamfv(ALFilter, Context, param, values);
ALfilter_setParamfv(ALFilter, Context, param, values);
}
UnlockFiltersWrite(Device);
UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@ -259,9 +243,9 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value
if(!Context) return;
Device = Context->Device;
LockFiltersRead(Device);
LockFilterList(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
else
{
if(param == AL_FILTER_TYPE)
@ -269,10 +253,10 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value
else
{
/* Call the appropriate handler */
ALfilter_GetParami(ALFilter, Context, param, value);
ALfilter_getParami(ALFilter, Context, param, value);
}
}
UnlockFiltersRead(Device);
UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@ -294,15 +278,15 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu
if(!Context) return;
Device = Context->Device;
LockFiltersRead(Device);
LockFilterList(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
else
{
/* Call the appropriate handler */
ALfilter_GetParamiv(ALFilter, Context, param, values);
ALfilter_getParamiv(ALFilter, Context, param, values);
}
UnlockFiltersRead(Device);
UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@ -317,15 +301,15 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val
if(!Context) return;
Device = Context->Device;
LockFiltersRead(Device);
LockFilterList(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
else
{
/* Call the appropriate handler */
ALfilter_GetParamf(ALFilter, Context, param, value);
ALfilter_getParamf(ALFilter, Context, param, value);
}
UnlockFiltersRead(Device);
UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@ -340,134 +324,52 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va
if(!Context) return;
Device = Context->Device;
LockFiltersRead(Device);
LockFilterList(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
else
{
/* Call the appropriate handler */
ALfilter_GetParamfv(ALFilter, Context, param, values);
ALfilter_getParamfv(ALFilter, Context, param, values);
}
UnlockFiltersRead(Device);
UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ)
{
ALfloat alpha, sqrtgain_alpha_2;
ALfloat w0, sin_w0, cos_w0;
ALfloat a[3] = { 1.0f, 0.0f, 0.0f };
ALfloat b[3] = { 1.0f, 0.0f, 0.0f };
// Limit gain to -100dB
gain = maxf(gain, 0.00001f);
w0 = F_TAU * freq_mult;
sin_w0 = sinf(w0);
cos_w0 = cosf(w0);
alpha = sin_w0/2.0f * rcpQ;
/* Calculate filter coefficients depending on filter type */
switch(type)
{
case ALfilterType_HighShelf:
sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 );
b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 );
a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
break;
case ALfilterType_LowShelf:
sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 );
b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 );
a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
break;
case ALfilterType_Peaking:
gain = sqrtf(gain);
b[0] = 1.0f + alpha * gain;
b[1] = -2.0f * cos_w0;
b[2] = 1.0f - alpha * gain;
a[0] = 1.0f + alpha / gain;
a[1] = -2.0f * cos_w0;
a[2] = 1.0f - alpha / gain;
break;
case ALfilterType_LowPass:
b[0] = (1.0f - cos_w0) / 2.0f;
b[1] = 1.0f - cos_w0;
b[2] = (1.0f - cos_w0) / 2.0f;
a[0] = 1.0f + alpha;
a[1] = -2.0f * cos_w0;
a[2] = 1.0f - alpha;
break;
case ALfilterType_HighPass:
b[0] = (1.0f + cos_w0) / 2.0f;
b[1] = -(1.0f + cos_w0);
b[2] = (1.0f + cos_w0) / 2.0f;
a[0] = 1.0f + alpha;
a[1] = -2.0f * cos_w0;
a[2] = 1.0f - alpha;
break;
case ALfilterType_BandPass:
b[0] = alpha;
b[1] = 0;
b[2] = -alpha;
a[0] = 1.0f + alpha;
a[1] = -2.0f * cos_w0;
a[2] = 1.0f - alpha;
break;
}
filter->a1 = a[1] / a[0];
filter->a2 = a[2] / a[0];
filter->b0 = b[0] / a[0];
filter->b1 = b[1] / a[0];
filter->b2 = b[2] / a[0];
}
static void lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
static void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); }
static void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); }
static void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_LOWPASS_GAIN:
if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val);
filter->Gain = val;
break;
case AL_LOWPASS_GAINHF:
if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val);
filter->GainHF = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param);
}
}
static void lp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
lp_SetParamf(filter, context, param, vals[0]);
}
static void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALlowpass_setParamf(filter, context, param, vals[0]); }
static void lp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
static void ALlowpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); }
static void ALlowpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); }
static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
@ -480,49 +382,47 @@ static void lp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param);
}
}
static void lp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{
lp_GetParamf(filter, context, param, vals);
}
static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALlowpass_getParamf(filter, context, param, vals); }
DEFINE_ALFILTER_VTABLE(ALlowpass);
static void hp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
static void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); }
static void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); }
static void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_HIGHPASS_GAIN:
if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range");
filter->Gain = val;
break;
case AL_HIGHPASS_GAINLF:
if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range");
filter->GainLF = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param);
}
}
static void hp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
hp_SetParamf(filter, context, param, vals[0]);
}
static void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALhighpass_setParamf(filter, context, param, vals[0]); }
static void hp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
static void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); }
static void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); }
static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
@ -535,55 +435,53 @@ static void hp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param);
}
}
static void hp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{
hp_GetParamf(filter, context, param, vals);
}
static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALhighpass_getParamf(filter, context, param, vals); }
DEFINE_ALFILTER_VTABLE(ALhighpass);
static void bp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
static void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); }
static void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); }
static void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_BANDPASS_GAIN:
if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range");
filter->Gain = val;
break;
case AL_BANDPASS_GAINHF:
if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range");
filter->GainHF = val;
break;
case AL_BANDPASS_GAINLF:
if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range");
filter->GainLF = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param);
}
}
static void bp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
bp_SetParamf(filter, context, param, vals[0]);
}
static void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALbandpass_setParamf(filter, context, param, vals[0]); }
static void bp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
static void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); }
static void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); }
static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
@ -600,47 +498,131 @@ static void bp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param);
}
}
static void bp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALbandpass_getParamf(filter, context, param, vals); }
DEFINE_ALFILTER_VTABLE(ALbandpass);
static void ALnullfilter_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
static void ALnullfilter_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
static void ALnullfilter_setParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat UNUSED(val))
{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
static void ALnullfilter_setParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals))
{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
static void ALnullfilter_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
static void ALnullfilter_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
static void ALnullfilter_getParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(val))
{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
static void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals))
{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
DEFINE_ALFILTER_VTABLE(ALnullfilter);
static ALfilter *AllocFilter(ALCcontext *context)
{
bp_GetParamf(filter, context, param, vals);
}
ALCdevice *device = context->Device;
FilterSubList *sublist, *subend;
ALfilter *filter = NULL;
ALsizei lidx = 0;
ALsizei slidx;
static void null_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_SetParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_SetParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALfloat *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
ALvoid ReleaseALFilters(ALCdevice *device)
{
ALsizei i;
for(i = 0;i < device->FilterMap.size;i++)
almtx_lock(&device->FilterLock);
sublist = VECTOR_BEGIN(device->FilterList);
subend = VECTOR_END(device->FilterList);
for(;sublist != subend;++sublist)
{
ALfilter *temp = device->FilterMap.values[i];
device->FilterMap.values[i] = NULL;
// Release filter structure
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALfilter));
al_free(temp);
if(sublist->FreeMask)
{
slidx = CTZ64(sublist->FreeMask);
filter = sublist->Filters + slidx;
break;
}
++lidx;
}
if(UNLIKELY(!filter))
{
const FilterSubList empty_sublist = { 0, NULL };
/* Don't allocate so many list entries that the 32-bit ID could
* overflow...
*/
if(UNLIKELY(VECTOR_SIZE(device->FilterList) >= 1<<25))
{
almtx_unlock(&device->FilterLock);
alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated");
return NULL;
}
lidx = (ALsizei)VECTOR_SIZE(device->FilterList);
VECTOR_PUSH_BACK(device->FilterList, empty_sublist);
sublist = &VECTOR_BACK(device->FilterList);
sublist->FreeMask = ~U64(0);
sublist->Filters = al_calloc(16, sizeof(ALfilter)*64);
if(UNLIKELY(!sublist->Filters))
{
VECTOR_POP_BACK(device->FilterList);
almtx_unlock(&device->FilterLock);
alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch");
return NULL;
}
slidx = 0;
filter = sublist->Filters + slidx;
}
memset(filter, 0, sizeof(*filter));
InitFilterParams(filter, AL_FILTER_NULL);
/* Add 1 to avoid filter ID 0. */
filter->id = ((lidx<<6) | slidx) + 1;
sublist->FreeMask &= ~(U64(1)<<slidx);
almtx_unlock(&device->FilterLock);
return filter;
}
static void FreeFilter(ALCdevice *device, ALfilter *filter)
{
ALuint id = filter->id - 1;
ALsizei lidx = id >> 6;
ALsizei slidx = id & 0x3f;
memset(filter, 0, sizeof(*filter));
VECTOR_ELEM(device->FilterList, lidx).FreeMask |= U64(1) << slidx;
}
void ReleaseALFilters(ALCdevice *device)
{
FilterSubList *sublist = VECTOR_BEGIN(device->FilterList);
FilterSubList *subend = VECTOR_END(device->FilterList);
size_t leftover = 0;
for(;sublist != subend;++sublist)
{
ALuint64 usemask = ~sublist->FreeMask;
while(usemask)
{
ALsizei idx = CTZ64(usemask);
ALfilter *filter = sublist->Filters + idx;
memset(filter, 0, sizeof(*filter));
++leftover;
usemask &= ~(U64(1) << idx);
}
sublist->FreeMask = ~usemask;
}
if(leftover > 0)
WARN("(%p) Deleted "SZFMT" Filter%s\n", device, leftover, (leftover==1)?"":"s");
}
@ -653,15 +635,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type)
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = 1.0f;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = lp_SetParami;
filter->SetParamiv = lp_SetParamiv;
filter->SetParamf = lp_SetParamf;
filter->SetParamfv = lp_SetParamfv;
filter->GetParami = lp_GetParami;
filter->GetParamiv = lp_GetParamiv;
filter->GetParamf = lp_GetParamf;
filter->GetParamfv = lp_GetParamfv;
filter->vtab = &ALlowpass_vtable;
}
else if(type == AL_FILTER_HIGHPASS)
{
@ -670,15 +644,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type)
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = hp_SetParami;
filter->SetParamiv = hp_SetParamiv;
filter->SetParamf = hp_SetParamf;
filter->SetParamfv = hp_SetParamfv;
filter->GetParami = hp_GetParami;
filter->GetParamiv = hp_GetParamiv;
filter->GetParamf = hp_GetParamf;
filter->GetParamfv = hp_GetParamfv;
filter->vtab = &ALhighpass_vtable;
}
else if(type == AL_FILTER_BANDPASS)
{
@ -687,15 +653,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type)
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = bp_SetParami;
filter->SetParamiv = bp_SetParamiv;
filter->SetParamf = bp_SetParamf;
filter->SetParamfv = bp_SetParamfv;
filter->GetParami = bp_GetParami;
filter->GetParamiv = bp_GetParamiv;
filter->GetParamf = bp_GetParamf;
filter->GetParamfv = bp_GetParamfv;
filter->vtab = &ALbandpass_vtable;
}
else
{
@ -704,15 +662,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type)
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = 1.0f;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = null_SetParami;
filter->SetParamiv = null_SetParamiv;
filter->SetParamf = null_SetParamf;
filter->SetParamfv = null_SetParamfv;
filter->GetParami = null_GetParami;
filter->GetParamiv = null_GetParamiv;
filter->GetParamf = null_GetParamf;
filter->GetParamfv = null_GetParamfv;
filter->vtab = &ALnullfilter_vtable;
}
filter->type = type;
}

View file

@ -21,85 +21,101 @@
#include "config.h"
#include "alMain.h"
#include "AL/alc.h"
#include "alu.h"
#include "alError.h"
#include "alListener.h"
#include "alSource.h"
#define DO_UPDATEPROPS() do { \
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
UpdateListenerProps(context); \
else \
ATOMIC_FLAG_CLEAR(&listener->PropsClean, almemory_order_release); \
} while(0)
AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
{
ALlistener *listener;
ALCcontext *context;
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
listener = context->Listener;
almtx_lock(&context->PropLock);
switch(param)
{
case AL_GAIN:
if(!(value >= 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->Gain = value;
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener gain out of range");
listener->Gain = value;
DO_UPDATEPROPS();
break;
case AL_METERS_PER_UNIT:
if(!(value >= 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->MetersPerUnit = value;
if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener meters per unit out of range");
context->MetersPerUnit = value;
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateContextProps(context);
else
ATOMIC_FLAG_CLEAR(&context->PropsClean, almemory_order_release);
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener float property");
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
almtx_unlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
{
ALlistener *listener;
ALCcontext *context;
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
listener = context->Listener;
almtx_lock(&context->PropLock);
switch(param)
{
case AL_POSITION:
if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->Position[0] = value1;
context->Listener->Position[1] = value2;
context->Listener->Position[2] = value3;
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener position out of range");
listener->Position[0] = value1;
listener->Position[1] = value2;
listener->Position[2] = value3;
DO_UPDATEPROPS();
break;
case AL_VELOCITY:
if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->Velocity[0] = value1;
context->Listener->Velocity[1] = value2;
context->Listener->Velocity[2] = value3;
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener velocity out of range");
listener->Velocity[0] = value1;
listener->Velocity[1] = value2;
listener->Velocity[2] = value3;
DO_UPDATEPROPS();
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property");
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
almtx_unlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
{
ALlistener *listener;
ALCcontext *context;
if(values)
@ -121,32 +137,31 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
listener = context->Listener;
almtx_lock(&context->PropLock);
if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer");
switch(param)
{
case AL_ORIENTATION:
if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener orientation out of range");
/* AT then UP */
context->Listener->Forward[0] = values[0];
context->Listener->Forward[1] = values[1];
context->Listener->Forward[2] = values[2];
context->Listener->Up[0] = values[3];
context->Listener->Up[1] = values[4];
context->Listener->Up[2] = values[5];
listener->Forward[0] = values[0];
listener->Forward[1] = values[1];
listener->Forward[2] = values[2];
listener->Up[0] = values[3];
listener->Up[1] = values[4];
listener->Up[2] = values[5];
DO_UPDATEPROPS();
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property");
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
almtx_unlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -158,17 +173,14 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
almtx_lock(&context->PropLock);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property");
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
almtx_unlock(&context->PropLock);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -188,17 +200,14 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
almtx_lock(&context->PropLock);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property");
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
almtx_unlock(&context->PropLock);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -232,19 +241,16 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
almtx_lock(&context->PropLock);
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property");
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
almtx_unlock(&context->PropLock);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -256,25 +262,24 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(value))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
almtx_lock(&context->PropLock);
if(!value)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
{
case AL_GAIN:
*value = context->Listener->Gain;
break;
case AL_METERS_PER_UNIT:
*value = context->Listener->MetersPerUnit;
*value = context->MetersPerUnit;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener float property");
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -286,10 +291,10 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(value1 && value2 && value3))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
almtx_lock(&context->PropLock);
if(!value1 || !value2 || !value3)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
{
case AL_POSITION:
*value1 = context->Listener->Position[0];
@ -304,11 +309,10 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property");
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -333,10 +337,10 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
almtx_lock(&context->PropLock);
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
{
case AL_ORIENTATION:
// AT then UP
@ -349,11 +353,10 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property");
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -365,17 +368,16 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(value))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
almtx_lock(&context->PropLock);
if(!value)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property");
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -387,10 +389,10 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(value1 && value2 && value3))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch (param)
almtx_lock(&context->PropLock);
if(!value1 || !value2 || !value3)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
{
case AL_POSITION:
*value1 = (ALint)context->Listener->Position[0];
@ -405,11 +407,10 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property");
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -429,10 +430,10 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
almtx_lock(&context->PropLock);
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
{
case AL_ORIENTATION:
// AT then UP
@ -445,11 +446,10 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property");
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -460,7 +460,7 @@ void UpdateListenerProps(ALCcontext *context)
struct ALlistenerProps *props;
/* Get an unused proprty container, or allocate a new one as needed. */
props = ATOMIC_LOAD(&listener->FreeList, almemory_order_acquire);
props = ATOMIC_LOAD(&context->FreeListenerProps, almemory_order_acquire);
if(!props)
props = al_calloc(16, sizeof(*props));
else
@ -468,48 +468,35 @@ void UpdateListenerProps(ALCcontext *context)
struct ALlistenerProps *next;
do {
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*,
&listener->FreeList, &props, next, almemory_order_seq_cst,
almemory_order_consume) == 0);
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeListenerProps, &props, next,
almemory_order_seq_cst, almemory_order_acquire) == 0);
}
/* Copy in current property values. */
ATOMIC_STORE(&props->Position[0], listener->Position[0], almemory_order_relaxed);
ATOMIC_STORE(&props->Position[1], listener->Position[1], almemory_order_relaxed);
ATOMIC_STORE(&props->Position[2], listener->Position[2], almemory_order_relaxed);
props->Position[0] = listener->Position[0];
props->Position[1] = listener->Position[1];
props->Position[2] = listener->Position[2];
ATOMIC_STORE(&props->Velocity[0], listener->Velocity[0], almemory_order_relaxed);
ATOMIC_STORE(&props->Velocity[1], listener->Velocity[1], almemory_order_relaxed);
ATOMIC_STORE(&props->Velocity[2], listener->Velocity[2], almemory_order_relaxed);
props->Velocity[0] = listener->Velocity[0];
props->Velocity[1] = listener->Velocity[1];
props->Velocity[2] = listener->Velocity[2];
ATOMIC_STORE(&props->Forward[0], listener->Forward[0], almemory_order_relaxed);
ATOMIC_STORE(&props->Forward[1], listener->Forward[1], almemory_order_relaxed);
ATOMIC_STORE(&props->Forward[2], listener->Forward[2], almemory_order_relaxed);
ATOMIC_STORE(&props->Up[0], listener->Up[0], almemory_order_relaxed);
ATOMIC_STORE(&props->Up[1], listener->Up[1], almemory_order_relaxed);
ATOMIC_STORE(&props->Up[2], listener->Up[2], almemory_order_relaxed);
props->Forward[0] = listener->Forward[0];
props->Forward[1] = listener->Forward[1];
props->Forward[2] = listener->Forward[2];
props->Up[0] = listener->Up[0];
props->Up[1] = listener->Up[1];
props->Up[2] = listener->Up[2];
ATOMIC_STORE(&props->Gain, listener->Gain, almemory_order_relaxed);
ATOMIC_STORE(&props->MetersPerUnit, listener->MetersPerUnit, almemory_order_relaxed);
ATOMIC_STORE(&props->DopplerFactor, context->DopplerFactor, almemory_order_relaxed);
ATOMIC_STORE(&props->DopplerVelocity, context->DopplerVelocity, almemory_order_relaxed);
ATOMIC_STORE(&props->SpeedOfSound, context->SpeedOfSound, almemory_order_relaxed);
ATOMIC_STORE(&props->SourceDistanceModel, context->SourceDistanceModel, almemory_order_relaxed);
ATOMIC_STORE(&props->DistanceModel, context->DistanceModel, almemory_order_relaxed);
props->Gain = listener->Gain;
/* Set the new container for updating internal parameters. */
props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &listener->Update, props, almemory_order_acq_rel);
props = ATOMIC_EXCHANGE_PTR(&listener->Update, props, almemory_order_acq_rel);
if(props)
{
/* If there was an unused update container, put it back in the
* freelist.
*/
struct ALlistenerProps *first = ATOMIC_LOAD(&listener->FreeList);
do {
ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*,
&listener->FreeList, &first, props) == 0);
ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &context->FreeListenerProps, props);
}
}

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,8 @@
#include "config.h"
#include "version.h"
#include <stdlib.h>
#include "alMain.h"
#include "AL/alc.h"
@ -45,6 +47,31 @@ static const ALchar alErrInvalidValue[] = "Invalid Value";
static const ALchar alErrInvalidOp[] = "Invalid Operation";
static const ALchar alErrOutOfMemory[] = "Out of Memory";
/* Resampler strings */
static const ALchar alPointResampler[] = "Nearest";
static const ALchar alLinearResampler[] = "Linear";
static const ALchar alCubicResampler[] = "Cubic";
static const ALchar alBSinc12Resampler[] = "11th order Sinc";
static const ALchar alBSinc24Resampler[] = "23rd order Sinc";
/* WARNING: Non-standard export! Not part of any extension, or exposed in the
* alcFunctions list.
*/
AL_API const ALchar* AL_APIENTRY alsoft_get_version(void)
{
const char *spoof = getenv("ALSOFT_SPOOF_VERSION");
if(spoof && spoof[0] != '\0') return spoof;
return ALSOFT_VERSION;
}
#define DO_UPDATEPROPS() do { \
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
UpdateContextProps(context); \
else \
ATOMIC_FLAG_CLEAR(&context->PropsClean, almemory_order_release); \
} while(0)
AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
{
ALCcontext *context;
@ -52,21 +79,19 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
almtx_lock(&context->PropLock);
switch(capability)
{
case AL_SOURCE_DISTANCE_MODEL:
context->SourceDistanceModel = AL_TRUE;
DO_UPDATEPROPS();
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
almtx_unlock(&context->PropLock);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -77,21 +102,19 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
almtx_lock(&context->PropLock);
switch(capability)
{
case AL_SOURCE_DISTANCE_MODEL:
context->SourceDistanceModel = AL_FALSE;
DO_UPDATEPROPS();
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
almtx_unlock(&context->PropLock);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -103,6 +126,7 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
context = GetContextRef();
if(!context) return AL_FALSE;
almtx_lock(&context->PropLock);
switch(capability)
{
case AL_SOURCE_DISTANCE_MODEL:
@ -110,12 +134,11 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability);
}
almtx_unlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
return value;
}
@ -127,6 +150,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
context = GetContextRef();
if(!context) return AL_FALSE;
almtx_lock(&context->PropLock);
switch(pname)
{
case AL_DOPPLER_FACTOR:
@ -150,7 +174,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll)
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
value = AL_TRUE;
break;
@ -159,13 +183,21 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
value = AL_TRUE;
break;
case AL_NUM_RESAMPLERS_SOFT:
/* Always non-0. */
value = AL_TRUE;
break;
case AL_DEFAULT_RESAMPLER_SOFT:
value = ResamplerDefault ? AL_TRUE : AL_FALSE;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname);
}
almtx_unlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
return value;
}
@ -177,6 +209,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
context = GetContextRef();
if(!context) return 0.0;
almtx_lock(&context->PropLock);
switch(pname)
{
case AL_DOPPLER_FACTOR:
@ -196,7 +229,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll)
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
value = (ALdouble)AL_TRUE;
break;
@ -204,13 +237,20 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
value = (ALdouble)GAIN_MIX_MAX/context->GainBoost;
break;
case AL_NUM_RESAMPLERS_SOFT:
value = (ALdouble)(ResamplerMax + 1);
break;
case AL_DEFAULT_RESAMPLER_SOFT:
value = (ALdouble)ResamplerDefault;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid double property 0x%04x", pname);
}
almtx_unlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
return value;
}
@ -222,6 +262,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
context = GetContextRef();
if(!context) return 0.0f;
almtx_lock(&context->PropLock);
switch(pname)
{
case AL_DOPPLER_FACTOR:
@ -241,7 +282,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll)
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
value = (ALfloat)AL_TRUE;
break;
@ -249,13 +290,20 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
value = GAIN_MIX_MAX/context->GainBoost;
break;
case AL_NUM_RESAMPLERS_SOFT:
value = (ALfloat)(ResamplerMax + 1);
break;
case AL_DEFAULT_RESAMPLER_SOFT:
value = (ALfloat)ResamplerDefault;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid float property 0x%04x", pname);
}
almtx_unlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
return value;
}
@ -267,6 +315,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
context = GetContextRef();
if(!context) return 0;
almtx_lock(&context->PropLock);
switch(pname)
{
case AL_DOPPLER_FACTOR:
@ -286,7 +335,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll)
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
value = (ALint)AL_TRUE;
break;
@ -294,13 +343,20 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
value = (ALint)(GAIN_MIX_MAX/context->GainBoost);
break;
case AL_NUM_RESAMPLERS_SOFT:
value = ResamplerMax + 1;
break;
case AL_DEFAULT_RESAMPLER_SOFT:
value = ResamplerDefault;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname);
}
almtx_unlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
return value;
}
@ -312,6 +368,7 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
context = GetContextRef();
if(!context) return 0;
almtx_lock(&context->PropLock);
switch(pname)
{
case AL_DOPPLER_FACTOR:
@ -331,7 +388,7 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll)
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
value = (ALint64SOFT)AL_TRUE;
break;
@ -339,13 +396,48 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost);
break;
case AL_NUM_RESAMPLERS_SOFT:
value = (ALint64SOFT)(ResamplerMax + 1);
break;
case AL_DEFAULT_RESAMPLER_SOFT:
value = (ALint64SOFT)ResamplerDefault;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname);
}
almtx_unlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
return value;
}
AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname)
{
ALCcontext *context;
void *value = NULL;
context = GetContextRef();
if(!context) return NULL;
almtx_lock(&context->PropLock);
switch(pname)
{
case AL_EVENT_CALLBACK_FUNCTION_SOFT:
value = context->EventCb;
break;
case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
value = context->EventParam;
break;
default:
alSetError(context, AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname);
}
almtx_unlock(&context->PropLock);
ALCcontext_DecRef(context);
return value;
}
@ -363,6 +455,8 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_GAIN_LIMIT_SOFT:
case AL_NUM_RESAMPLERS_SOFT:
case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetBoolean(pname);
return;
}
@ -371,15 +465,14 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
context = GetContextRef();
if(!context) return;
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
switch(pname)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname);
}
done:
ALCcontext_DecRef(context);
}
@ -397,6 +490,8 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_GAIN_LIMIT_SOFT:
case AL_NUM_RESAMPLERS_SOFT:
case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetDouble(pname);
return;
}
@ -405,15 +500,14 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
context = GetContextRef();
if(!context) return;
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
switch(pname)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname);
}
done:
ALCcontext_DecRef(context);
}
@ -431,6 +525,8 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_GAIN_LIMIT_SOFT:
case AL_NUM_RESAMPLERS_SOFT:
case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetFloat(pname);
return;
}
@ -439,15 +535,14 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
context = GetContextRef();
if(!context) return;
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
switch(pname)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname);
}
done:
ALCcontext_DecRef(context);
}
@ -465,6 +560,8 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_GAIN_LIMIT_SOFT:
case AL_NUM_RESAMPLERS_SOFT:
case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetInteger(pname);
return;
}
@ -473,13 +570,14 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
context = GetContextRef();
if(!context) return;
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
switch(pname)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname);
}
done:
ALCcontext_DecRef(context);
}
@ -497,6 +595,8 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_GAIN_LIMIT_SOFT:
case AL_NUM_RESAMPLERS_SOFT:
case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetInteger64SOFT(pname);
return;
}
@ -505,13 +605,43 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
context = GetContextRef();
if(!context) return;
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
switch(pname)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname);
}
ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values)
{
ALCcontext *context;
if(values)
{
switch(pname)
{
case AL_EVENT_CALLBACK_FUNCTION_SOFT:
case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
values[0] = alGetPointerSOFT(pname);
return;
}
}
context = GetContextRef();
if(!context) return;
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
switch(pname)
{
default:
alSetError(context, AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname);
}
done:
ALCcontext_DecRef(context);
}
@ -566,12 +696,10 @@ AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
alSetError(context, AL_INVALID_VALUE, "Invalid string property 0x%04x", pname);
}
done:
ALCcontext_DecRef(context);
return value;
}
@ -583,15 +711,15 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
if(!context) return;
if(!(value >= 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
alSetError(context, AL_INVALID_VALUE, "Doppler factor %f out of range", value);
else
{
almtx_lock(&context->PropLock);
context->DopplerFactor = value;
DO_UPDATEPROPS();
almtx_unlock(&context->PropLock);
}
WriteLock(&context->PropLock);
context->DopplerFactor = value;
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
WriteUnlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
}
@ -602,16 +730,30 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
context = GetContextRef();
if(!context) return;
if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Deprecated))
{
static const ALCchar msg[] =
"alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound";
const ALsizei msglen = (ALsizei)strlen(msg);
ALbitfieldSOFT enabledevts;
almtx_lock(&context->EventCbLock);
enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed);
if((enabledevts&EventType_Deprecated) && context->EventCb)
(*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg,
context->EventParam);
almtx_unlock(&context->EventCbLock);
}
if(!(value >= 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
alSetError(context, AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
else
{
almtx_lock(&context->PropLock);
context->DopplerVelocity = value;
DO_UPDATEPROPS();
almtx_unlock(&context->PropLock);
}
WriteLock(&context->PropLock);
context->DopplerVelocity = value;
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
WriteUnlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
}
@ -623,15 +765,15 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value)
if(!context) return;
if(!(value > 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
alSetError(context, AL_INVALID_VALUE, "Speed of sound %f out of range", value);
else
{
almtx_lock(&context->PropLock);
context->SpeedOfSound = value;
DO_UPDATEPROPS();
almtx_unlock(&context->PropLock);
}
WriteLock(&context->PropLock);
context->SpeedOfSound = value;
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
WriteUnlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
}
@ -646,18 +788,16 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED ||
value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED ||
value == AL_NONE))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
WriteLock(&context->PropLock);
context->DistanceModel = value;
if(!context->SourceDistanceModel)
alSetError(context, AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
else
{
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
almtx_lock(&context->PropLock);
context->DistanceModel = value;
if(!context->SourceDistanceModel)
DO_UPDATEPROPS();
almtx_unlock(&context->PropLock);
}
WriteUnlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
}
@ -669,7 +809,7 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
context = GetContextRef();
if(!context) return;
ALCcontext_DeferUpdates(context, DeferAll);
ALCcontext_DeferUpdates(context);
ALCcontext_DecRef(context);
}
@ -685,3 +825,76 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
ALCcontext_DecRef(context);
}
AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
{
const char *ResamplerNames[] = {
alPointResampler, alLinearResampler,
alCubicResampler, alBSinc12Resampler,
alBSinc24Resampler,
};
const ALchar *value = NULL;
ALCcontext *context;
static_assert(COUNTOF(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list");
context = GetContextRef();
if(!context) return NULL;
switch(pname)
{
case AL_RESAMPLER_NAME_SOFT:
if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Resampler name index %d out of range",
index);
value = ResamplerNames[index];
break;
default:
alSetError(context, AL_INVALID_VALUE, "Invalid string indexed property");
}
done:
ALCcontext_DecRef(context);
return value;
}
void UpdateContextProps(ALCcontext *context)
{
struct ALcontextProps *props;
/* Get an unused proprty container, or allocate a new one as needed. */
props = ATOMIC_LOAD(&context->FreeContextProps, almemory_order_acquire);
if(!props)
props = al_calloc(16, sizeof(*props));
else
{
struct ALcontextProps *next;
do {
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeContextProps, &props, next,
almemory_order_seq_cst, almemory_order_acquire) == 0);
}
/* Copy in current property values. */
props->MetersPerUnit = context->MetersPerUnit;
props->DopplerFactor = context->DopplerFactor;
props->DopplerVelocity = context->DopplerVelocity;
props->SpeedOfSound = context->SpeedOfSound;
props->SourceDistanceModel = context->SourceDistanceModel;
props->DistanceModel = context->DistanceModel;
/* Set the new container for updating internal parameters. */
props = ATOMIC_EXCHANGE_PTR(&context->Update, props, almemory_order_acq_rel);
if(props)
{
/* If there was an unused update container, put it back in the
* freelist.
*/
ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &context->FreeContextProps, props);
}
}

View file

@ -1,105 +0,0 @@
/**
* 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
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include "alMain.h"
#include "alThunk.h"
#include "almalloc.h"
static ATOMIC(ALenum) *ThunkArray;
static ALuint ThunkArraySize;
static RWLock ThunkLock;
void ThunkInit(void)
{
RWLockInit(&ThunkLock);
ThunkArraySize = 1024;
ThunkArray = al_calloc(16, ThunkArraySize * sizeof(*ThunkArray));
}
void ThunkExit(void)
{
al_free(ThunkArray);
ThunkArray = NULL;
ThunkArraySize = 0;
}
ALenum NewThunkEntry(ALuint *index)
{
void *NewList;
ALuint i;
ReadLock(&ThunkLock);
for(i = 0;i < ThunkArraySize;i++)
{
if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE)
{
ReadUnlock(&ThunkLock);
*index = i+1;
return AL_NO_ERROR;
}
}
ReadUnlock(&ThunkLock);
WriteLock(&ThunkLock);
/* Double-check that there's still no free entries, in case another
* invocation just came through and increased the size of the array.
*/
for(;i < ThunkArraySize;i++)
{
if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE)
{
WriteUnlock(&ThunkLock);
*index = i+1;
return AL_NO_ERROR;
}
}
NewList = al_calloc(16, ThunkArraySize*2 * sizeof(*ThunkArray));
if(!NewList)
{
WriteUnlock(&ThunkLock);
ERR("Realloc failed to increase to %u entries!\n", ThunkArraySize*2);
return AL_OUT_OF_MEMORY;
}
memcpy(NewList, ThunkArray, ThunkArraySize*sizeof(*ThunkArray));
al_free(ThunkArray);
ThunkArray = NewList;
ThunkArraySize *= 2;
ATOMIC_STORE(&ThunkArray[i], AL_TRUE);
WriteUnlock(&ThunkLock);
*index = i+1;
return AL_NO_ERROR;
}
void FreeThunkEntry(ALuint index)
{
ReadLock(&ThunkLock);
if(index > 0 && index <= ThunkArraySize)
ATOMIC_STORE(&ThunkArray[index-1], AL_FALSE);
ReadUnlock(&ThunkLock);
}

View file

@ -0,0 +1,140 @@
#include "config.h"
#include "AL/alc.h"
#include "AL/al.h"
#include "AL/alext.h"
#include "alMain.h"
#include "alError.h"
#include "ringbuffer.h"
static int EventThread(void *arg)
{
ALCcontext *context = arg;
/* Clear all pending posts on the semaphore. */
while(alsem_trywait(&context->EventSem) == althrd_success)
{
}
while(1)
{
ALbitfieldSOFT enabledevts;
AsyncEvent evt;
if(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) == 0)
{
alsem_wait(&context->EventSem);
continue;
}
if(!evt.EnumType)
break;
almtx_lock(&context->EventCbLock);
enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire);
if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType)
context->EventCb(evt.Type, evt.ObjectId, evt.Param, (ALsizei)strlen(evt.Message),
evt.Message, context->EventParam);
almtx_unlock(&context->EventCbLock);
}
return 0;
}
AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable)
{
ALCcontext *context;
ALbitfieldSOFT enabledevts;
ALbitfieldSOFT flags = 0;
bool isrunning;
ALsizei i;
context = GetContextRef();
if(!context) return;
if(count < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Controlling %d events", count);
if(count == 0) goto done;
if(!types) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer");
for(i = 0;i < count;i++)
{
if(types[i] == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT)
flags |= EventType_BufferCompleted;
else if(types[i] == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT)
flags |= EventType_SourceStateChange;
else if(types[i] == AL_EVENT_TYPE_ERROR_SOFT)
flags |= EventType_Error;
else if(types[i] == AL_EVENT_TYPE_PERFORMANCE_SOFT)
flags |= EventType_Performance;
else if(types[i] == AL_EVENT_TYPE_DEPRECATED_SOFT)
flags |= EventType_Deprecated;
else if(types[i] == AL_EVENT_TYPE_DISCONNECTED_SOFT)
flags |= EventType_Disconnected;
else
SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid event type 0x%04x", types[i]);
}
almtx_lock(&context->EventThrdLock);
if(enable)
{
if(!context->AsyncEvents)
context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false);
enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed);
isrunning = !!enabledevts;
while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts|flags,
almemory_order_acq_rel, almemory_order_acquire) == 0)
{
/* enabledevts is (re-)filled with the current value on failure, so
* just try again.
*/
}
if(!isrunning && flags)
althrd_create(&context->EventThread, EventThread, context);
}
else
{
enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed);
isrunning = !!enabledevts;
while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts&~flags,
almemory_order_acq_rel, almemory_order_acquire) == 0)
{
}
if(isrunning && !(enabledevts&~flags))
{
static const AsyncEvent kill_evt = { 0 };
while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0)
althrd_yield();
alsem_post(&context->EventSem);
althrd_join(context->EventThread, NULL);
}
else
{
/* Wait to ensure the event handler sees the changed flags before
* returning.
*/
almtx_lock(&context->EventCbLock);
almtx_unlock(&context->EventCbLock);
}
}
almtx_unlock(&context->EventThrdLock);
done:
ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
almtx_lock(&context->EventCbLock);
context->EventCb = callback;
context->EventParam = userParam;
almtx_unlock(&context->EventCbLock);
almtx_unlock(&context->PropLock);
ALCcontext_DecRef(context);
}

File diff suppressed because it is too large Load diff