mirror of
https://github.com/love2d/megasource.git
synced 2026-08-21 05:02:11 +02:00
Update OpenAL Soft to commit 414b56edec5441211dc924fef365c54267c04f1c
This commit is contained in:
@@ -29,16 +29,21 @@ 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 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_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)); } \
|
||||
@@ -54,21 +59,22 @@ 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, \
|
||||
}
|
||||
|
||||
|
||||
@@ -110,17 +116,18 @@ typedef struct ALeffectslot {
|
||||
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;
|
||||
@@ -133,9 +140,9 @@ typedef struct ALeffectslot {
|
||||
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
|
||||
@@ -144,44 +151,30 @@ typedef struct ALeffectslot {
|
||||
alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE];
|
||||
} 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
|
||||
}
|
||||
|
||||
@@ -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,29 +15,25 @@ 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,
|
||||
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 */
|
||||
};
|
||||
|
||||
ALsizei BytesFromUserFmt(enum UserFmtType type);
|
||||
@@ -44,9 +46,12 @@ inline ALsizei 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,
|
||||
@@ -72,18 +77,17 @@ inline ALsizei 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;
|
||||
@@ -91,34 +95,17 @@ typedef struct ALbuffer {
|
||||
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
|
||||
|
||||
@@ -10,23 +10,32 @@ extern "C" {
|
||||
struct ALeffect;
|
||||
|
||||
enum {
|
||||
AL__EAXREVERB = 0,
|
||||
AL__REVERB,
|
||||
AL__CHORUS,
|
||||
AL__COMPRESSOR,
|
||||
AL__DISTORTION,
|
||||
AL__ECHO,
|
||||
AL__EQUALIZER,
|
||||
AL__FLANGER,
|
||||
AL__MODULATOR,
|
||||
AL__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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,99 +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 b0, b1, b2; /* Transfer function coefficients "b" */
|
||||
ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */
|
||||
} 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);
|
||||
|
||||
inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src)
|
||||
{
|
||||
dst->b0 = src->b0;
|
||||
dst->b1 = src->b1;
|
||||
dst->b2 = src->b2;
|
||||
dst->a1 = src->a1;
|
||||
dst->a2 = src->a2;
|
||||
}
|
||||
|
||||
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples);
|
||||
|
||||
inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei 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, ...)
|
||||
@@ -117,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
|
||||
}
|
||||
|
||||
@@ -8,19 +8,23 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ALcontextProps {
|
||||
ALfloat DopplerFactor;
|
||||
ALfloat DopplerVelocity;
|
||||
ALfloat SpeedOfSound;
|
||||
ALboolean SourceDistanceModel;
|
||||
enum DistanceModel DistanceModel;
|
||||
ALfloat MetersPerUnit;
|
||||
|
||||
ATOMIC(struct ALcontextProps*) next;
|
||||
};
|
||||
|
||||
struct ALlistenerProps {
|
||||
ALfloat Position[3];
|
||||
ALfloat Velocity[3];
|
||||
ALfloat Forward[3];
|
||||
ALfloat Up[3];
|
||||
ALfloat Gain;
|
||||
ALfloat MetersPerUnit;
|
||||
|
||||
ALfloat DopplerFactor;
|
||||
ALfloat DopplerVelocity;
|
||||
ALfloat SpeedOfSound;
|
||||
ALboolean SourceDistanceModel;
|
||||
enum DistanceModel DistanceModel;
|
||||
|
||||
ATOMIC(struct ALlistenerProps*) next;
|
||||
};
|
||||
@@ -31,17 +35,13 @@ typedef struct ALlistener {
|
||||
ALfloat Forward[3];
|
||||
ALfloat Up[3];
|
||||
ALfloat Gain;
|
||||
ALfloat MetersPerUnit;
|
||||
|
||||
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;
|
||||
|
||||
@@ -12,133 +12,25 @@
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FENV_H
|
||||
#include <fenv.h>
|
||||
#ifdef HAVE_INTRIN_H
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/alext.h"
|
||||
|
||||
#include "inprogext.h"
|
||||
#include "logging.h"
|
||||
#include "polymorphism.h"
|
||||
#include "static_assert.h"
|
||||
#include "align.h"
|
||||
#include "atomic.h"
|
||||
#include "uintmap.h"
|
||||
#include "vector.h"
|
||||
#include "alstring.h"
|
||||
#include "almalloc.h"
|
||||
#include "threads.h"
|
||||
|
||||
#ifndef ALC_SOFT_loopback2
|
||||
#define ALC_SOFT_loopback2 1
|
||||
#define ALC_AMBISONIC_LAYOUT_SOFT 0x1997
|
||||
#define ALC_AMBISONIC_SCALING_SOFT 0x1998
|
||||
#define ALC_AMBISONIC_ORDER_SOFT 0x1999
|
||||
|
||||
#define ALC_BFORMAT3D_SOFT 0x1508
|
||||
|
||||
/* Ambisonic layouts */
|
||||
#define ALC_ACN_SOFT 0x1600
|
||||
#define ALC_FUMA_SOFT 0x1601
|
||||
|
||||
/* Ambisonic scalings (normalization) */
|
||||
/*#define ALC_FUMA_SOFT*/
|
||||
#define ALC_SN3D_SOFT 0x1602
|
||||
#define ALC_N3D_SOFT 0x1603
|
||||
|
||||
typedef ALCboolean (ALC_APIENTRY*LPALCISAMBISONICFORMATSUPPORTEDSOFT)(ALCdevice *device, ALCenum layout, ALCenum scaling, ALsizei order);
|
||||
#ifdef AL_ALEXT_PROTOTYPES
|
||||
ALC_API ALCboolean ALC_APIENTRY alcIsAmbisonicFormatSupportedSOFT(ALCdevice *device, ALCenum layout, ALCenum scaling, ALsizei order);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ALC_SOFT_device_clock
|
||||
#define ALC_SOFT_device_clock 1
|
||||
typedef int64_t ALCint64SOFT;
|
||||
typedef uint64_t ALCuint64SOFT;
|
||||
#define ALC_DEVICE_CLOCK_SOFT 0x1600
|
||||
#define ALC_DEVICE_LATENCY_SOFT 0x1601
|
||||
#define ALC_DEVICE_CLOCK_LATENCY_SOFT 0x1602
|
||||
typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values);
|
||||
#ifdef AL_ALEXT_PROTOTYPES
|
||||
ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef AL_SOFT_buffer_samples2
|
||||
#define AL_SOFT_buffer_samples2 1
|
||||
/* Channel configurations */
|
||||
#define AL_MONO_SOFT 0x1500
|
||||
#define AL_STEREO_SOFT 0x1501
|
||||
#define AL_REAR_SOFT 0x1502
|
||||
#define AL_QUAD_SOFT 0x1503
|
||||
#define AL_5POINT1_SOFT 0x1504
|
||||
#define AL_6POINT1_SOFT 0x1505
|
||||
#define AL_7POINT1_SOFT 0x1506
|
||||
#define AL_BFORMAT2D_SOFT 0x1507
|
||||
#define AL_BFORMAT3D_SOFT 0x1508
|
||||
|
||||
/* Sample types */
|
||||
#define AL_BYTE_SOFT 0x1400
|
||||
#define AL_UNSIGNED_BYTE_SOFT 0x1401
|
||||
#define AL_SHORT_SOFT 0x1402
|
||||
#define AL_UNSIGNED_SHORT_SOFT 0x1403
|
||||
#define AL_INT_SOFT 0x1404
|
||||
#define AL_UNSIGNED_INT_SOFT 0x1405
|
||||
#define AL_FLOAT_SOFT 0x1406
|
||||
#define AL_DOUBLE_SOFT 0x1407
|
||||
#define AL_BYTE3_SOFT 0x1408
|
||||
#define AL_UNSIGNED_BYTE3_SOFT 0x1409
|
||||
#define AL_MULAW_SOFT 0x140A
|
||||
|
||||
/* Storage formats */
|
||||
#define AL_MONO8_SOFT 0x1100
|
||||
#define AL_MONO16_SOFT 0x1101
|
||||
#define AL_MONO32F_SOFT 0x10010
|
||||
#define AL_STEREO8_SOFT 0x1102
|
||||
#define AL_STEREO16_SOFT 0x1103
|
||||
#define AL_STEREO32F_SOFT 0x10011
|
||||
#define AL_QUAD8_SOFT 0x1204
|
||||
#define AL_QUAD16_SOFT 0x1205
|
||||
#define AL_QUAD32F_SOFT 0x1206
|
||||
#define AL_REAR8_SOFT 0x1207
|
||||
#define AL_REAR16_SOFT 0x1208
|
||||
#define AL_REAR32F_SOFT 0x1209
|
||||
#define AL_5POINT1_8_SOFT 0x120A
|
||||
#define AL_5POINT1_16_SOFT 0x120B
|
||||
#define AL_5POINT1_32F_SOFT 0x120C
|
||||
#define AL_6POINT1_8_SOFT 0x120D
|
||||
#define AL_6POINT1_16_SOFT 0x120E
|
||||
#define AL_6POINT1_32F_SOFT 0x120F
|
||||
#define AL_7POINT1_8_SOFT 0x1210
|
||||
#define AL_7POINT1_16_SOFT 0x1211
|
||||
#define AL_7POINT1_32F_SOFT 0x1212
|
||||
#define AL_BFORMAT2D_8_SOFT 0x20021
|
||||
#define AL_BFORMAT2D_16_SOFT 0x20022
|
||||
#define AL_BFORMAT2D_32F_SOFT 0x20023
|
||||
#define AL_BFORMAT3D_8_SOFT 0x20031
|
||||
#define AL_BFORMAT3D_16_SOFT 0x20032
|
||||
#define AL_BFORMAT3D_32F_SOFT 0x20033
|
||||
|
||||
/* Buffer attributes */
|
||||
#define AL_INTERNAL_FORMAT_SOFT 0x2008
|
||||
#define AL_BYTE_LENGTH_SOFT 0x2009
|
||||
#define AL_SAMPLE_LENGTH_SOFT 0x200A
|
||||
#define AL_SEC_LENGTH_SOFT 0x200B
|
||||
|
||||
#if 0
|
||||
typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*);
|
||||
typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*);
|
||||
typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum);
|
||||
#ifdef AL_ALEXT_PROTOTYPES
|
||||
AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data);
|
||||
AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data);
|
||||
AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_WIN64)
|
||||
#define SZFMT "%I64u"
|
||||
@@ -150,72 +42,11 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format);
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
/* Because of a long-standing deficiency in C, you're not allowed to implicitly
|
||||
* cast a pointer-to-type-array to a pointer-to-const-type-array. For example,
|
||||
*
|
||||
* int (*ptr)[10];
|
||||
* const int (*cptr)[10] = ptr;
|
||||
*
|
||||
* is not allowed and most compilers will generate noisy warnings about
|
||||
* incompatible types, even though it just makes the array elements const.
|
||||
* Clang will allow it if you make the array type a typedef, like this:
|
||||
*
|
||||
* typedef int int10[10];
|
||||
* int10 *ptr;
|
||||
* const int10 *cptr = ptr;
|
||||
*
|
||||
* however GCC does not and still issues the incompatible type warning. The
|
||||
* "proper" way to fix it is to add an explicit cast for the constified type,
|
||||
* but that removes the vast majority of otherwise useful type-checking you'd
|
||||
* get, and runs the risk of improper casts if types are later changed. Leaving
|
||||
* it non-const can also be an issue if you use it as a function parameter, and
|
||||
* happen to have a const type as input (and also reduce the capabilities of
|
||||
* the compiler to better optimize the function).
|
||||
*
|
||||
* So to work around the problem, we use a macro. The macro first assigns the
|
||||
* incoming variable to the specified non-const type to ensure it's the correct
|
||||
* type, then casts the variable as the desired constified type. Very ugly, but
|
||||
* I'd rather not have hundreds of lines of warnings because I want to tell the
|
||||
* compiler that some array(s) can't be changed by the code, or have lots of
|
||||
* error-prone casts.
|
||||
*/
|
||||
#define SAFE_CONST(T, var) __extension__({ \
|
||||
T _tmp = (var); \
|
||||
(const T)_tmp; \
|
||||
})
|
||||
#define LIKELY(x) __builtin_expect(!!(x), !0)
|
||||
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
/* Non-GNU-compatible compilers have to use a straight cast with no extra
|
||||
* checks, due to the lack of multi-statement expressions.
|
||||
*/
|
||||
#define SAFE_CONST(T, var) ((const T)(var))
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
/* This helps cast away the const-ness of a pointer without accidentally
|
||||
* changing the pointer type. This is necessary due to Clang's inability to use
|
||||
* atomic_load on a const _Atomic variable.
|
||||
*/
|
||||
#define CONST_CAST(T, V) __extension__({ \
|
||||
const T _tmp = (V); \
|
||||
(T)_tmp; \
|
||||
})
|
||||
#else
|
||||
#define CONST_CAST(T, V) ((T)(V))
|
||||
#endif
|
||||
|
||||
|
||||
typedef ALint64SOFT ALint64;
|
||||
typedef ALuint64SOFT ALuint64;
|
||||
|
||||
#ifndef U64
|
||||
#if defined(_MSC_VER)
|
||||
#define U64(x) ((ALuint64)(x##ui64))
|
||||
#elif SIZEOF_LONG == 8
|
||||
#define U64(x) ((ALuint64)(x##ul))
|
||||
#elif SIZEOF_LONG_LONG == 8
|
||||
#define U64(x) ((ALuint64)(x##ull))
|
||||
#endif
|
||||
#define LIKELY(x) (!!(x))
|
||||
#define UNLIKELY(x) (!!(x))
|
||||
#endif
|
||||
|
||||
#ifndef UINT64_MAX
|
||||
@@ -234,42 +65,88 @@ typedef ALuint64SOFT ALuint64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z))))
|
||||
#else
|
||||
#define DECL_FORMAT(x, y, z)
|
||||
#endif
|
||||
|
||||
/* Calculates the size of a struct with N elements of a flexible array member.
|
||||
* GCC and Clang allow offsetof(Type, fam[N]) for this, but MSVC seems to have
|
||||
* trouble, so a bit more verbose workaround is needed.
|
||||
*/
|
||||
#define FAM_SIZE(T, M, N) (offsetof(T, M) + sizeof(((T*)NULL)->M[0])*(N))
|
||||
|
||||
#if defined(__GNUC__) && defined(__i386__)
|
||||
/* force_align_arg_pointer is required for proper function arguments aligning
|
||||
* when SSE code is used. Some systems (Windows, QNX) do not guarantee our
|
||||
* thread functions will be properly aligned on the stack, even though GCC may
|
||||
* generate code with the assumption that it is. */
|
||||
#define FORCE_ALIGN __attribute__((force_align_arg_pointer))
|
||||
#else
|
||||
#define FORCE_ALIGN
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_C99_VLA
|
||||
#define DECL_VLA(T, _name, _size) T _name[(_size)]
|
||||
#else
|
||||
#define DECL_VLA(T, _name, _size) T *_name = alloca((_size) * sizeof(T))
|
||||
#endif
|
||||
typedef ALint64SOFT ALint64;
|
||||
typedef ALuint64SOFT ALuint64;
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#ifdef MAX_PATH
|
||||
#define PATH_MAX MAX_PATH
|
||||
#else
|
||||
#define PATH_MAX 4096
|
||||
#ifndef U64
|
||||
#if defined(_MSC_VER)
|
||||
#define U64(x) ((ALuint64)(x##ui64))
|
||||
#elif SIZEOF_LONG == 8
|
||||
#define U64(x) ((ALuint64)(x##ul))
|
||||
#elif SIZEOF_LONG_LONG == 8
|
||||
#define U64(x) ((ALuint64)(x##ull))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define a CTZ64 macro (count trailing zeros, for 64-bit integers). The result
|
||||
* is *UNDEFINED* if the value is 0.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if SIZEOF_LONG == 8
|
||||
#define CTZ64(x) __builtin_ctzl(x)
|
||||
#else
|
||||
#define CTZ64(x) __builtin_ctzll(x)
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_BITSCANFORWARD64_INTRINSIC)
|
||||
|
||||
inline int msvc64_ctz64(ALuint64 v)
|
||||
{
|
||||
unsigned long idx = 64;
|
||||
_BitScanForward64(&idx, v);
|
||||
return (int)idx;
|
||||
}
|
||||
#define CTZ64(x) msvc64_ctz64(x)
|
||||
|
||||
#elif defined(HAVE_BITSCANFORWARD_INTRINSIC)
|
||||
|
||||
inline int msvc_ctz64(ALuint64 v)
|
||||
{
|
||||
unsigned long idx = 64;
|
||||
if(!_BitScanForward(&idx, v&0xffffffff))
|
||||
{
|
||||
if(_BitScanForward(&idx, v>>32))
|
||||
idx += 32;
|
||||
}
|
||||
return (int)idx;
|
||||
}
|
||||
#define CTZ64(x) msvc_ctz64(x)
|
||||
|
||||
#else
|
||||
|
||||
/* There be black magics here. The popcnt64 method is derived from
|
||||
* https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
|
||||
* while the ctz-utilizing-popcnt algorithm is shown here
|
||||
* http://www.hackersdelight.org/hdcodetxt/ntz.c.txt
|
||||
* as the ntz2 variant. These likely aren't the most efficient methods, but
|
||||
* they're good enough if the GCC or MSVC intrinsics aren't available.
|
||||
*/
|
||||
inline int fallback_popcnt64(ALuint64 v)
|
||||
{
|
||||
v = v - ((v >> 1) & U64(0x5555555555555555));
|
||||
v = (v & U64(0x3333333333333333)) + ((v >> 2) & U64(0x3333333333333333));
|
||||
v = (v + (v >> 4)) & U64(0x0f0f0f0f0f0f0f0f);
|
||||
return (int)((v * U64(0x0101010101010101)) >> 56);
|
||||
}
|
||||
|
||||
inline int fallback_ctz64(ALuint64 value)
|
||||
{
|
||||
return fallback_popcnt64(~value & (value - 1));
|
||||
}
|
||||
#define CTZ64(x) fallback_ctz64(x)
|
||||
#endif
|
||||
|
||||
static const union {
|
||||
ALuint u;
|
||||
@@ -280,107 +157,21 @@ static const union {
|
||||
#define COUNTOF(x) (sizeof(x) / sizeof(0[x]))
|
||||
|
||||
|
||||
#define DERIVE_FROM_TYPE(t) t t##_parent
|
||||
#define STATIC_CAST(to, obj) (&(obj)->to##_parent)
|
||||
#ifdef __GNUC__
|
||||
#define STATIC_UPCAST(to, from, obj) __extension__({ \
|
||||
static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \
|
||||
"Invalid upcast object from type"); \
|
||||
(to*)((char*)(obj) - offsetof(to, from##_parent)); \
|
||||
})
|
||||
#else
|
||||
#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent)))
|
||||
#endif
|
||||
|
||||
#define DECLARE_FORWARD(T1, T2, rettype, func) \
|
||||
rettype T1##_##func(T1 *obj) \
|
||||
{ return T2##_##func(STATIC_CAST(T2, obj)); }
|
||||
|
||||
#define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \
|
||||
rettype T1##_##func(T1 *obj, argtype1 a) \
|
||||
{ return T2##_##func(STATIC_CAST(T2, obj), a); }
|
||||
|
||||
#define DECLARE_FORWARD2(T1, T2, rettype, func, argtype1, argtype2) \
|
||||
rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b) \
|
||||
{ return T2##_##func(STATIC_CAST(T2, obj), a, b); }
|
||||
|
||||
#define DECLARE_FORWARD3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
|
||||
rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b, argtype3 c) \
|
||||
{ return T2##_##func(STATIC_CAST(T2, obj), a, b, c); }
|
||||
|
||||
|
||||
#define GET_VTABLE1(T1) (&(T1##_vtable))
|
||||
#define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable))
|
||||
|
||||
#define SET_VTABLE1(T1, obj) ((obj)->vtbl = GET_VTABLE1(T1))
|
||||
#define SET_VTABLE2(T1, T2, obj) (STATIC_CAST(T2, obj)->vtbl = GET_VTABLE2(T1, T2))
|
||||
|
||||
#define DECLARE_THUNK(T1, T2, rettype, func) \
|
||||
static rettype T1##_##T2##_##func(T2 *obj) \
|
||||
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj)); }
|
||||
|
||||
#define DECLARE_THUNK1(T1, T2, rettype, func, argtype1) \
|
||||
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a) \
|
||||
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a); }
|
||||
|
||||
#define DECLARE_THUNK2(T1, T2, rettype, func, argtype1, argtype2) \
|
||||
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \
|
||||
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b); }
|
||||
|
||||
#define DECLARE_THUNK3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
|
||||
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \
|
||||
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); }
|
||||
|
||||
#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \
|
||||
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \
|
||||
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); }
|
||||
|
||||
#define DECLARE_DEFAULT_ALLOCATORS(T) \
|
||||
static void* T##_New(size_t size) { return al_malloc(16, size); } \
|
||||
static void T##_Delete(void *ptr) { al_free(ptr); }
|
||||
|
||||
/* Helper to extract an argument list for VCALL. Not used directly. */
|
||||
#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
|
||||
|
||||
/* Call a "virtual" method on an object, with arguments. */
|
||||
#define V(obj, func) ((obj)->vtbl->func((obj), EXTRACT_VCALL_ARGS
|
||||
/* Call a "virtual" method on an object, with no arguments. */
|
||||
#define V0(obj, func) ((obj)->vtbl->func((obj) EXTRACT_VCALL_ARGS
|
||||
|
||||
#define DELETE_OBJ(obj) do { \
|
||||
if((obj) != NULL) \
|
||||
{ \
|
||||
V0((obj),Destruct)(); \
|
||||
V0((obj),Delete)(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define NEW_OBJ(_res, T) do { \
|
||||
_res = T##_New(sizeof(T)); \
|
||||
if(_res) \
|
||||
{ \
|
||||
memset(_res, 0, sizeof(T)); \
|
||||
T##_Construct(_res, EXTRACT_NEW_ARGS
|
||||
#define NEW_OBJ0(_res, T) do { \
|
||||
_res = T##_New(sizeof(T)); \
|
||||
if(_res) \
|
||||
{ \
|
||||
memset(_res, 0, sizeof(T)); \
|
||||
T##_Construct(_res EXTRACT_NEW_ARGS
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ll_ringbuffer;
|
||||
struct Hrtf;
|
||||
struct HrtfEntry;
|
||||
struct DirectHrtfState;
|
||||
struct FrontStablizer;
|
||||
struct Compressor;
|
||||
struct ALCbackend;
|
||||
struct ALbuffer;
|
||||
struct ALeffect;
|
||||
struct ALfilter;
|
||||
struct ALsource;
|
||||
struct ALcontextProps;
|
||||
struct ALlistenerProps;
|
||||
struct ALvoiceProps;
|
||||
struct ALeffectslotProps;
|
||||
|
||||
|
||||
#define DEFAULT_OUTPUT_RATE (44100)
|
||||
@@ -409,24 +200,6 @@ inline size_t RoundUp(size_t value, size_t r)
|
||||
return value - (value%r);
|
||||
}
|
||||
|
||||
/* Scales the given value using 64-bit integer math, rounding the result. */
|
||||
inline ALuint64 ScaleRound(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale)
|
||||
{
|
||||
return (val*new_scale + old_scale/2) / old_scale;
|
||||
}
|
||||
|
||||
/* Scales the given value using 64-bit integer math, flooring the result. */
|
||||
inline ALuint64 ScaleFloor(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale)
|
||||
{
|
||||
return val * new_scale / old_scale;
|
||||
}
|
||||
|
||||
/* Scales the given value using 64-bit integer math, ceiling the result. */
|
||||
inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale)
|
||||
{
|
||||
return (val*new_scale + old_scale-1) / old_scale;
|
||||
}
|
||||
|
||||
/* Fast float-to-int conversion. Assumes the FPU is already in round-to-zero
|
||||
* mode. */
|
||||
inline ALint fastf2i(ALfloat f)
|
||||
@@ -449,8 +222,6 @@ enum DevProbe {
|
||||
CAPTURE_DEVICE_PROBE
|
||||
};
|
||||
|
||||
struct ALCbackend;
|
||||
|
||||
|
||||
enum DistanceModel {
|
||||
InverseDistanceClamped = AL_INVERSE_DISTANCE_CLAMPED,
|
||||
@@ -556,14 +327,6 @@ enum AmbiNorm {
|
||||
};
|
||||
|
||||
|
||||
extern const struct EffectList {
|
||||
const char *name;
|
||||
int type;
|
||||
const char *ename;
|
||||
ALenum val;
|
||||
} EffectList[];
|
||||
|
||||
|
||||
enum DeviceType {
|
||||
Playback,
|
||||
Capture,
|
||||
@@ -614,34 +377,36 @@ typedef union AmbiConfig {
|
||||
} AmbiConfig;
|
||||
|
||||
|
||||
#define HRTF_HISTORY_BITS (6)
|
||||
#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
|
||||
#define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1)
|
||||
typedef struct BufferSubList {
|
||||
ALuint64 FreeMask;
|
||||
struct ALbuffer *Buffers; /* 64 */
|
||||
} BufferSubList;
|
||||
TYPEDEF_VECTOR(BufferSubList, vector_BufferSubList)
|
||||
|
||||
#define HRIR_BITS (7)
|
||||
#define HRIR_LENGTH (1<<HRIR_BITS)
|
||||
#define HRIR_MASK (HRIR_LENGTH-1)
|
||||
typedef struct EffectSubList {
|
||||
ALuint64 FreeMask;
|
||||
struct ALeffect *Effects; /* 64 */
|
||||
} EffectSubList;
|
||||
TYPEDEF_VECTOR(EffectSubList, vector_EffectSubList)
|
||||
|
||||
typedef struct HrtfState {
|
||||
alignas(16) ALfloat History[HRTF_HISTORY_LENGTH];
|
||||
alignas(16) ALfloat Values[HRIR_LENGTH][2];
|
||||
} HrtfState;
|
||||
typedef struct FilterSubList {
|
||||
ALuint64 FreeMask;
|
||||
struct ALfilter *Filters; /* 64 */
|
||||
} FilterSubList;
|
||||
TYPEDEF_VECTOR(FilterSubList, vector_FilterSubList)
|
||||
|
||||
typedef struct HrtfParams {
|
||||
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
|
||||
ALsizei Delay[2];
|
||||
ALfloat Gain;
|
||||
} HrtfParams;
|
||||
typedef struct SourceSubList {
|
||||
ALuint64 FreeMask;
|
||||
struct ALsource *Sources; /* 64 */
|
||||
} SourceSubList;
|
||||
TYPEDEF_VECTOR(SourceSubList, vector_SourceSubList)
|
||||
|
||||
/* Effect slots are rather large, and apps aren't likely to have more than one
|
||||
* or two (let alone 64), so hold them individually.
|
||||
*/
|
||||
typedef struct ALeffectslot *ALeffectslotPtr;
|
||||
TYPEDEF_VECTOR(ALeffectslotPtr, vector_ALeffectslotPtr)
|
||||
|
||||
typedef struct DirectHrtfState {
|
||||
/* HRTF filter state for dry buffer content */
|
||||
ALsizei Offset;
|
||||
ALsizei IrSize;
|
||||
struct {
|
||||
alignas(16) ALfloat Values[HRIR_LENGTH][2];
|
||||
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
|
||||
} Chan[];
|
||||
} DirectHrtfState;
|
||||
|
||||
typedef struct EnumeratedHrtf {
|
||||
al_string name;
|
||||
@@ -667,11 +432,41 @@ typedef struct DistanceComp {
|
||||
*/
|
||||
#define BUFFERSIZE 2048
|
||||
|
||||
struct ALCdevice_struct
|
||||
{
|
||||
typedef struct DryMixParams {
|
||||
AmbiConfig Ambi;
|
||||
/* Number of coefficients in each Ambi.Coeffs to mix together (4 for first-
|
||||
* order, 9 for second-order, etc). If the count is 0, Ambi.Map is used
|
||||
* instead to map each output to a coefficient index.
|
||||
*/
|
||||
ALsizei CoeffCount;
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1];
|
||||
} DryMixParams;
|
||||
|
||||
typedef struct BFMixParams {
|
||||
AmbiConfig Ambi;
|
||||
/* Will only be 4 or 0. */
|
||||
ALsizei CoeffCount;
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
} BFMixParams;
|
||||
|
||||
typedef struct RealMixParams {
|
||||
enum Channel ChannelName[MAX_OUTPUT_CHANNELS];
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
} RealMixParams;
|
||||
|
||||
typedef void (*POSTPROCESS)(ALCdevice *device, ALsizei SamplesToDo);
|
||||
|
||||
struct ALCdevice_struct {
|
||||
RefCount ref;
|
||||
|
||||
ALCboolean Connected;
|
||||
ATOMIC(ALenum) Connected;
|
||||
enum DeviceType Type;
|
||||
|
||||
ALuint Frequency;
|
||||
@@ -701,16 +496,21 @@ struct ALCdevice_struct
|
||||
ALsizei NumAuxSends;
|
||||
|
||||
// Map of Buffers for this device
|
||||
UIntMap BufferMap;
|
||||
vector_BufferSubList BufferList;
|
||||
almtx_t BufferLock;
|
||||
|
||||
// Map of Effects for this device
|
||||
UIntMap EffectMap;
|
||||
vector_EffectSubList EffectList;
|
||||
almtx_t EffectLock;
|
||||
|
||||
// Map of Filters for this device
|
||||
UIntMap FilterMap;
|
||||
vector_FilterSubList FilterList;
|
||||
almtx_t FilterLock;
|
||||
|
||||
POSTPROCESS PostProcess;
|
||||
|
||||
/* HRTF state and info */
|
||||
DirectHrtfState *Hrtf;
|
||||
struct DirectHrtfState *Hrtf;
|
||||
al_string HrtfName;
|
||||
struct Hrtf *HrtfHandle;
|
||||
vector_EnumeratedHrtf HrtfList;
|
||||
@@ -737,45 +537,21 @@ struct ALCdevice_struct
|
||||
ALuint64 ClockBase;
|
||||
ALuint SamplesDone;
|
||||
|
||||
/* Temp storage used for each source when mixing. */
|
||||
alignas(16) ALfloat SourceData[BUFFERSIZE];
|
||||
alignas(16) ALfloat ResampledData[BUFFERSIZE];
|
||||
alignas(16) ALfloat FilteredData[BUFFERSIZE];
|
||||
alignas(16) ALfloat NFCtrlData[BUFFERSIZE];
|
||||
/* Temp storage used for mixer processing. */
|
||||
alignas(16) ALfloat TempBuffer[4][BUFFERSIZE];
|
||||
|
||||
/* The "dry" path corresponds to the main output. */
|
||||
struct {
|
||||
AmbiConfig Ambi;
|
||||
/* Number of coefficients in each Ambi.Coeffs to mix together (4 for
|
||||
* first-order, 9 for second-order, etc). If the count is 0, Ambi.Map
|
||||
* is used instead to map each output to a coefficient index.
|
||||
*/
|
||||
ALsizei CoeffCount;
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1];
|
||||
} Dry;
|
||||
DryMixParams Dry;
|
||||
|
||||
/* First-order ambisonics output, to be upsampled to the dry buffer if different. */
|
||||
struct {
|
||||
AmbiConfig Ambi;
|
||||
/* Will only be 4 or 0. */
|
||||
ALsizei CoeffCount;
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
} FOAOut;
|
||||
BFMixParams FOAOut;
|
||||
|
||||
/* "Real" output, which will be written to the device buffer. May alias the
|
||||
* dry buffer.
|
||||
*/
|
||||
struct {
|
||||
enum Channel ChannelName[MAX_OUTPUT_CHANNELS];
|
||||
RealMixParams RealOut;
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
} RealOut;
|
||||
struct FrontStablizer *Stablizer;
|
||||
|
||||
struct Compressor *Limiter;
|
||||
|
||||
@@ -804,7 +580,7 @@ struct ALCdevice_struct
|
||||
almtx_t BackendLock;
|
||||
struct ALCbackend *Backend;
|
||||
|
||||
ALCdevice *volatile next;
|
||||
ATOMIC(ALCdevice*) next;
|
||||
};
|
||||
|
||||
// Frequency was requested by the app or config file
|
||||
@@ -832,13 +608,34 @@ struct ALCdevice_struct
|
||||
#define RECORD_THREAD_NAME "alsoft-record"
|
||||
|
||||
|
||||
enum {
|
||||
EventType_SourceStateChange = 1<<0,
|
||||
EventType_BufferCompleted = 1<<1,
|
||||
EventType_Error = 1<<2,
|
||||
EventType_Performance = 1<<3,
|
||||
EventType_Deprecated = 1<<4,
|
||||
EventType_Disconnected = 1<<5,
|
||||
};
|
||||
|
||||
typedef struct AsyncEvent {
|
||||
unsigned int EnumType;
|
||||
ALenum Type;
|
||||
ALuint ObjectId;
|
||||
ALuint Param;
|
||||
ALchar Message[1008];
|
||||
} AsyncEvent;
|
||||
|
||||
struct ALCcontext_struct {
|
||||
RefCount ref;
|
||||
|
||||
struct ALlistener *Listener;
|
||||
|
||||
UIntMap SourceMap;
|
||||
UIntMap EffectSlotMap;
|
||||
vector_SourceSubList SourceList;
|
||||
ALuint NumSources;
|
||||
almtx_t SourceLock;
|
||||
|
||||
vector_ALeffectslotPtr EffectSlotList;
|
||||
almtx_t EffectSlotLock;
|
||||
|
||||
ATOMIC(ALenum) LastError;
|
||||
|
||||
@@ -848,9 +645,12 @@ struct ALCcontext_struct {
|
||||
ALfloat DopplerFactor;
|
||||
ALfloat DopplerVelocity;
|
||||
ALfloat SpeedOfSound;
|
||||
ALfloat MetersPerUnit;
|
||||
|
||||
ATOMIC_FLAG PropsClean;
|
||||
ATOMIC(ALenum) DeferUpdates;
|
||||
|
||||
RWLock PropLock;
|
||||
almtx_t PropLock;
|
||||
|
||||
/* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
|
||||
* indicates if updates are currently happening).
|
||||
@@ -860,19 +660,38 @@ struct ALCcontext_struct {
|
||||
|
||||
ALfloat GainBoost;
|
||||
|
||||
ATOMIC(struct ALcontextProps*) Update;
|
||||
|
||||
/* Linked lists of unused property containers, free to use for future
|
||||
* updates.
|
||||
*/
|
||||
ATOMIC(struct ALcontextProps*) FreeContextProps;
|
||||
ATOMIC(struct ALlistenerProps*) FreeListenerProps;
|
||||
ATOMIC(struct ALvoiceProps*) FreeVoiceProps;
|
||||
ATOMIC(struct ALeffectslotProps*) FreeEffectslotProps;
|
||||
|
||||
struct ALvoice **Voices;
|
||||
ALsizei VoiceCount;
|
||||
ALsizei MaxVoices;
|
||||
|
||||
ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots;
|
||||
|
||||
almtx_t EventThrdLock;
|
||||
althrd_t EventThread;
|
||||
alsem_t EventSem;
|
||||
struct ll_ringbuffer *AsyncEvents;
|
||||
ATOMIC(ALbitfieldSOFT) EnabledEvts;
|
||||
almtx_t EventCbLock;
|
||||
ALEVENTPROCSOFT EventCb;
|
||||
void *EventParam;
|
||||
|
||||
/* Default effect slot */
|
||||
struct ALeffectslot *DefaultSlot;
|
||||
|
||||
ALCdevice *Device;
|
||||
const ALCchar *ExtensionList;
|
||||
|
||||
ALCcontext *volatile next;
|
||||
ATOMIC(ALCcontext*) next;
|
||||
|
||||
/* Memory space used by the listener (and possibly default effect slot) */
|
||||
alignas(16) ALCbyte _listener_mem[];
|
||||
@@ -880,79 +699,18 @@ struct ALCcontext_struct {
|
||||
|
||||
ALCcontext *GetContextRef(void);
|
||||
|
||||
void ALCcontext_IncRef(ALCcontext *context);
|
||||
void ALCcontext_DecRef(ALCcontext *context);
|
||||
|
||||
void ALCcontext_DeferUpdates(ALCcontext *context);
|
||||
void ALCcontext_ProcessUpdates(ALCcontext *context);
|
||||
|
||||
void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends);
|
||||
|
||||
void AppendAllDevicesList(const ALCchar *name);
|
||||
void AppendCaptureDeviceList(const ALCchar *name);
|
||||
|
||||
void ALCdevice_Lock(ALCdevice *device);
|
||||
void ALCdevice_Unlock(ALCdevice *device);
|
||||
|
||||
void ALCcontext_DeferUpdates(ALCcontext *context);
|
||||
void ALCcontext_ProcessUpdates(ALCcontext *context);
|
||||
|
||||
|
||||
typedef struct {
|
||||
#ifdef HAVE_FENV_H
|
||||
DERIVE_FROM_TYPE(fenv_t);
|
||||
#ifdef _WIN32
|
||||
int round_mode;
|
||||
#endif
|
||||
#else
|
||||
int state;
|
||||
#endif
|
||||
#ifdef HAVE_SSE
|
||||
int sse_state;
|
||||
#endif
|
||||
} FPUCtl;
|
||||
void SetMixerFPUMode(FPUCtl *ctl);
|
||||
void RestoreFPUMode(const FPUCtl *ctl);
|
||||
#ifdef __GNUC__
|
||||
/* Use an alternate macro set with GCC to avoid accidental continue or break
|
||||
* statements within the mixer mode.
|
||||
*/
|
||||
#define START_MIXER_MODE() __extension__({ FPUCtl _oldMode; SetMixerFPUMode(&_oldMode);
|
||||
#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); })
|
||||
#else
|
||||
#define START_MIXER_MODE() do { FPUCtl _oldMode; SetMixerFPUMode(&_oldMode);
|
||||
#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); } while(0)
|
||||
#endif
|
||||
#define LEAVE_MIXER_MODE() RestoreFPUMode(&_oldMode)
|
||||
|
||||
|
||||
typedef struct ll_ringbuffer ll_ringbuffer_t;
|
||||
typedef struct ll_ringbuffer_data {
|
||||
char *buf;
|
||||
size_t len;
|
||||
} ll_ringbuffer_data_t;
|
||||
ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz);
|
||||
void ll_ringbuffer_free(ll_ringbuffer_t *rb);
|
||||
void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec);
|
||||
void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec);
|
||||
size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt);
|
||||
size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt);
|
||||
void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt);
|
||||
size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb);
|
||||
int ll_ringbuffer_mlock(ll_ringbuffer_t *rb);
|
||||
void ll_ringbuffer_reset(ll_ringbuffer_t *rb);
|
||||
size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt);
|
||||
void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt);
|
||||
size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb);
|
||||
|
||||
void ReadALConfig(void);
|
||||
void FreeALConfig(void);
|
||||
int ConfigValueExists(const char *devName, const char *blockName, const char *keyName);
|
||||
const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def);
|
||||
int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def);
|
||||
int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret);
|
||||
int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret);
|
||||
int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret);
|
||||
int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret);
|
||||
int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret);
|
||||
|
||||
extern ALint RTPrioLevel;
|
||||
void SetRTPriority(void);
|
||||
|
||||
void SetDefaultChannelOrder(ALCdevice *device);
|
||||
@@ -961,12 +719,6 @@ void SetDefaultWFXChannelOrder(ALCdevice *device);
|
||||
const ALCchar *DevFmtTypeString(enum DevFmtType type);
|
||||
const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans);
|
||||
|
||||
/**
|
||||
* GetChannelIdxByName
|
||||
*
|
||||
* Returns the index for the given channel name (e.g. FrontCenter), or -1 if it
|
||||
* doesn't exist.
|
||||
*/
|
||||
inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan)
|
||||
{
|
||||
ALint i;
|
||||
@@ -977,107 +729,33 @@ inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#define GetChannelIdxByName(x, c) GetChannelIndex((x).ChannelName, (c))
|
||||
|
||||
extern FILE *LogFile;
|
||||
|
||||
#if defined(__GNUC__) && !defined(_WIN32) && !defined(IN_IDE_PARSER)
|
||||
#define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: "MSG, T, __FUNCTION__ , ## __VA_ARGS__)
|
||||
#else
|
||||
void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4);
|
||||
#define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s: "MSG, __FUNCTION__ , ## __VA_ARGS__)
|
||||
#else
|
||||
#define LOG_ANDROID(T, MSG, ...) ((void)0)
|
||||
#endif
|
||||
|
||||
enum LogLevel {
|
||||
NoLog,
|
||||
LogError,
|
||||
LogWarning,
|
||||
LogTrace,
|
||||
LogRef
|
||||
};
|
||||
extern enum LogLevel LogLevel;
|
||||
|
||||
#define TRACEREF(...) do { \
|
||||
if(LogLevel >= LogRef) \
|
||||
AL_PRINT("(--)", __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define TRACE(...) do { \
|
||||
if(LogLevel >= LogTrace) \
|
||||
AL_PRINT("(II)", __VA_ARGS__); \
|
||||
LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define WARN(...) do { \
|
||||
if(LogLevel >= LogWarning) \
|
||||
AL_PRINT("(WW)", __VA_ARGS__); \
|
||||
LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define ERR(...) do { \
|
||||
if(LogLevel >= LogError) \
|
||||
AL_PRINT("(EE)", __VA_ARGS__); \
|
||||
LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \
|
||||
} while(0)
|
||||
/**
|
||||
* GetChannelIdxByName
|
||||
*
|
||||
* Returns the index for the given channel name (e.g. FrontCenter), or -1 if it
|
||||
* doesn't exist.
|
||||
*/
|
||||
inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan)
|
||||
{ return GetChannelIndex(real->ChannelName, chan); }
|
||||
|
||||
|
||||
extern ALint RTPrioLevel;
|
||||
inline void LockBufferList(ALCdevice *device) { almtx_lock(&device->BufferLock); }
|
||||
inline void UnlockBufferList(ALCdevice *device) { almtx_unlock(&device->BufferLock); }
|
||||
|
||||
inline void LockEffectList(ALCdevice *device) { almtx_lock(&device->EffectLock); }
|
||||
inline void UnlockEffectList(ALCdevice *device) { almtx_unlock(&device->EffectLock); }
|
||||
|
||||
extern ALuint CPUCapFlags;
|
||||
enum {
|
||||
CPU_CAP_SSE = 1<<0,
|
||||
CPU_CAP_SSE2 = 1<<1,
|
||||
CPU_CAP_SSE3 = 1<<2,
|
||||
CPU_CAP_SSE4_1 = 1<<3,
|
||||
CPU_CAP_NEON = 1<<4,
|
||||
};
|
||||
inline void LockFilterList(ALCdevice *device) { almtx_lock(&device->FilterLock); }
|
||||
inline void UnlockFilterList(ALCdevice *device) { almtx_unlock(&device->FilterLock); }
|
||||
|
||||
inline void LockEffectSlotList(ALCcontext *context)
|
||||
{ almtx_lock(&context->EffectSlotLock); }
|
||||
inline void UnlockEffectSlotList(ALCcontext *context)
|
||||
{ almtx_unlock(&context->EffectSlotLock); }
|
||||
|
||||
void FillCPUCaps(ALuint capfilter);
|
||||
|
||||
vector_al_string SearchDataFiles(const char *match, const char *subdir);
|
||||
|
||||
/* Small hack to use a pointer-to-array types as a normal argument type.
|
||||
* Shouldn't be used directly.
|
||||
*/
|
||||
typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
|
||||
typedef ALfloat ALfloat2[2];
|
||||
|
||||
|
||||
/* The compressor requires the following information for proper
|
||||
* initialization:
|
||||
*
|
||||
* PreGainDb - Gain applied before detection (in dB).
|
||||
* PostGainDb - Gain applied after compression (in dB).
|
||||
* SummedLink - Whether to use summed (true) or maxed (false) linking.
|
||||
* RmsSensing - Whether to use RMS (true) or Peak (false) sensing.
|
||||
* AttackTimeMin - Minimum attack time (in seconds).
|
||||
* AttackTimeMax - Maximum attack time. Automates when min != max.
|
||||
* ReleaseTimeMin - Minimum release time (in seconds).
|
||||
* ReleaseTimeMax - Maximum release time. Automates when min != max.
|
||||
* Ratio - Compression ratio (x:1). Set to 0 for true limiter.
|
||||
* ThresholdDb - Triggering threshold (in dB).
|
||||
* KneeDb - Knee width (below threshold; in dB).
|
||||
* SampleRate - Sample rate to process.
|
||||
*/
|
||||
struct Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb,
|
||||
const ALboolean SummedLink, const ALboolean RmsSensing, const ALfloat AttackTimeMin,
|
||||
const ALfloat AttackTimeMax, const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax,
|
||||
const ALfloat Ratio, const ALfloat ThresholdDb, const ALfloat KneeDb,
|
||||
const ALuint SampleRate);
|
||||
|
||||
ALuint GetCompressorSampleRate(const struct Compressor *Comp);
|
||||
|
||||
void ApplyCompression(struct Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
|
||||
ALfloat (*restrict OutBuffer)[BUFFERSIZE]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -19,8 +19,10 @@ struct ALsource;
|
||||
|
||||
|
||||
typedef struct ALbufferlistitem {
|
||||
struct ALbuffer *buffer;
|
||||
ATOMIC(struct ALbufferlistitem*) next;
|
||||
ALsizei max_samples;
|
||||
ALsizei num_buffers;
|
||||
struct ALbuffer *buffers[];
|
||||
} ALbufferlistitem;
|
||||
|
||||
|
||||
@@ -91,32 +93,22 @@ typedef struct ALsource {
|
||||
ALint SourceType;
|
||||
|
||||
/** Source state (initial, playing, paused, or stopped) */
|
||||
ATOMIC(ALenum) state;
|
||||
ALenum state;
|
||||
|
||||
/** Source Buffer Queue head. */
|
||||
RWLock queue_lock;
|
||||
ALbufferlistitem *queue;
|
||||
|
||||
ATOMIC_FLAG PropsClean;
|
||||
|
||||
/* Index into the context's Voices array. Lazily updated, only checked and
|
||||
* reset when looking up the voice.
|
||||
*/
|
||||
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 ReleaseALSources(ALCcontext *Context);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,28 +12,27 @@
|
||||
|
||||
#include "alMain.h"
|
||||
#include "alBuffer.h"
|
||||
#include "alFilter.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
|
||||
#include "hrtf.h"
|
||||
#include "align.h"
|
||||
#include "nfcfilter.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 ALbufferlistitem;
|
||||
struct ALvoice;
|
||||
@@ -53,13 +52,16 @@ enum Resampler {
|
||||
PointResampler,
|
||||
LinearResampler,
|
||||
FIR4Resampler,
|
||||
BSincResampler,
|
||||
BSinc12Resampler,
|
||||
BSinc24Resampler,
|
||||
|
||||
ResamplerMax = BSincResampler
|
||||
ResamplerMax = BSinc24Resampler
|
||||
};
|
||||
extern enum Resampler ResamplerDefault;
|
||||
|
||||
/* The number of distinct scale and phase intervals within the filter table. */
|
||||
/* 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
|
||||
@@ -71,27 +73,29 @@ extern enum Resampler ResamplerDefault;
|
||||
*/
|
||||
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;
|
||||
|
||||
ALboolean BsincPrepare(const ALuint increment, BsincState *state);
|
||||
|
||||
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];
|
||||
@@ -149,10 +153,10 @@ typedef struct MixHrtfParams {
|
||||
|
||||
|
||||
typedef struct DirectParams {
|
||||
ALfilterState LowPass;
|
||||
ALfilterState HighPass;
|
||||
BiquadState LowPass;
|
||||
BiquadState HighPass;
|
||||
|
||||
NfcFilter NFCtrlFilter[MAX_AMBI_ORDER];
|
||||
NfcFilter NFCtrlFilter;
|
||||
|
||||
struct {
|
||||
HrtfParams Old;
|
||||
@@ -167,8 +171,8 @@ typedef struct DirectParams {
|
||||
} DirectParams;
|
||||
|
||||
typedef struct SendParams {
|
||||
ALfilterState LowPass;
|
||||
ALfilterState HighPass;
|
||||
BiquadState LowPass;
|
||||
BiquadState HighPass;
|
||||
|
||||
struct {
|
||||
ALfloat Current[MAX_OUTPUT_CHANNELS];
|
||||
@@ -231,16 +235,15 @@ struct ALvoiceProps {
|
||||
} Send[];
|
||||
};
|
||||
|
||||
/* If not 'fading', gain targets are used directly without fading. */
|
||||
#define VOICE_IS_FADING (1<<0)
|
||||
#define VOICE_HAS_HRTF (1<<1)
|
||||
#define VOICE_HAS_NFC (1<<2)
|
||||
#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 ALvoiceProps*) FreeList;
|
||||
|
||||
ATOMIC(struct ALsource*) Source;
|
||||
ATOMIC(bool) Playing;
|
||||
@@ -277,7 +280,7 @@ typedef struct ALvoice {
|
||||
|
||||
ALuint Offset; /* Number of output samples mixed since starting. */
|
||||
|
||||
alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES];
|
||||
alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_RESAMPLE_PADDING];
|
||||
|
||||
InterpState ResampleState;
|
||||
|
||||
@@ -381,19 +384,26 @@ inline ALuint64 maxu64(ALuint64 a, ALuint64 b)
|
||||
inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
|
||||
{ return minu64(max, maxu64(min, val)); }
|
||||
|
||||
|
||||
extern alignas(16) const ALfloat bsincTab[18840];
|
||||
extern alignas(16) const ALfloat sinc4Tab[FRACTIONONE][4];
|
||||
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, ALsizei frac)
|
||||
inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu)
|
||||
{
|
||||
return sinc4Tab[frac][0]*val0 + sinc4Tab[frac][1]*val1 +
|
||||
sinc4Tab[frac][2]*val2 + sinc4Tab[frac][3]*val3;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -403,10 +413,10 @@ enum HrtfRequestMode {
|
||||
Hrtf_Disable = 2,
|
||||
};
|
||||
|
||||
void aluInit(void);
|
||||
|
||||
void aluInitMixer(void);
|
||||
|
||||
MixerFunc SelectMixer(void);
|
||||
RowMixerFunc SelectRowMixer(void);
|
||||
ResamplerFunc SelectResampler(enum Resampler resampler);
|
||||
|
||||
/* aluInitRenderer
|
||||
@@ -418,6 +428,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
|
||||
|
||||
void aluInitEffectPanning(struct ALeffectslot *slot);
|
||||
|
||||
void aluSelectPostProcess(ALCdevice *device);
|
||||
|
||||
/**
|
||||
* CalcDirectionCoeffs
|
||||
*
|
||||
@@ -454,35 +466,26 @@ inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread,
|
||||
*/
|
||||
void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
|
||||
|
||||
/**
|
||||
* ComputeAmbientGains
|
||||
*
|
||||
* Computes channel gains for ambient, omni-directional sounds.
|
||||
*/
|
||||
#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, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
|
||||
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, 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]);
|
||||
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
|
||||
*
|
||||
@@ -490,24 +493,29 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, con
|
||||
* 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, 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]);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
ALboolean MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo);
|
||||
ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo);
|
||||
|
||||
void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples);
|
||||
/* Caller must lock the device. */
|
||||
void aluHandleDisconnect(ALCdevice *device);
|
||||
/* 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
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -27,36 +27,79 @@
|
||||
#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 UIntMap EffectStateFactoryMap;
|
||||
static inline ALeffectStateFactory *getFactoryByType(ALenum type)
|
||||
static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context);
|
||||
static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context);
|
||||
|
||||
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 \
|
||||
ATOMIC_FLAG_CLEAR(&slot->PropsClean, almemory_order_release); \
|
||||
} while(0)
|
||||
@@ -64,77 +107,62 @@ static void ALeffectState_DecRef(ALeffectState *state);
|
||||
|
||||
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
|
||||
{
|
||||
ALCdevice *device;
|
||||
ALCcontext *context;
|
||||
ALeffectslot **tmpslots = NULL;
|
||||
ALsizei cur;
|
||||
ALenum err;
|
||||
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
if(!(n >= 0))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
tmpslots = al_malloc(DEF_ALIGN, sizeof(ALeffectslot*)*n);
|
||||
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n);
|
||||
if(n == 0) goto done;
|
||||
|
||||
LockEffectSlotsWrite(context);
|
||||
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);
|
||||
UnlockEffectSlotsWrite(context);
|
||||
UnlockEffectSlotList(context);
|
||||
|
||||
alDeleteAuxiliaryEffectSlots(cur, effectslots);
|
||||
SET_ERROR_AND_GOTO(context, err, done);
|
||||
SETERR_GOTO(context, err, done, "Effect slot object allocation failed");
|
||||
}
|
||||
|
||||
err = NewThunkEntry(&slot->id);
|
||||
if(err == AL_NO_ERROR)
|
||||
err = InsertUIntMapEntryNoLock(&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);
|
||||
UnlockEffectSlotsWrite(context);
|
||||
|
||||
alDeleteAuxiliaryEffectSlots(cur, effectslots);
|
||||
SET_ERROR_AND_GOTO(context, err, done);
|
||||
}
|
||||
|
||||
aluInitEffectPanning(slot);
|
||||
|
||||
tmpslots[cur] = slot;
|
||||
slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1;
|
||||
*iter = slot;
|
||||
|
||||
effectslots[cur] = slot->id;
|
||||
}
|
||||
if(n > 0)
|
||||
{
|
||||
struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire);
|
||||
struct ALeffectslotArray *newarray = NULL;
|
||||
ALsizei newcount = curarray->count + n;
|
||||
ALCdevice *device;
|
||||
|
||||
newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount));
|
||||
newarray->count = newcount;
|
||||
memcpy(newarray->slot, tmpslots, sizeof(ALeffectslot*)*n);
|
||||
if(curarray)
|
||||
memcpy(newarray->slot+n, curarray->slot, sizeof(ALeffectslot*)*curarray->count);
|
||||
|
||||
newarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray,
|
||||
almemory_order_acq_rel);
|
||||
device = context->Device;
|
||||
while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
|
||||
althrd_yield();
|
||||
al_free(newarray);
|
||||
}
|
||||
UnlockEffectSlotsWrite(context);
|
||||
AddActiveEffectSlots(effectslots, n, context);
|
||||
UnlockEffectSlotList(context);
|
||||
|
||||
done:
|
||||
al_free(tmpslots);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@@ -147,54 +175,28 @@ 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
|
||||
if(n > 0)
|
||||
{
|
||||
struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire);
|
||||
struct ALeffectslotArray *newarray = NULL;
|
||||
ALsizei newcount = curarray->count - n;
|
||||
ALCdevice *device;
|
||||
ALsizei j, k;
|
||||
|
||||
assert(newcount >= 0);
|
||||
newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount));
|
||||
newarray->count = newcount;
|
||||
for(i = j = 0;i < newarray->count;)
|
||||
{
|
||||
slot = curarray->slot[j++];
|
||||
for(k = 0;k < n;k++)
|
||||
{
|
||||
if(slot->id == effectslots[k])
|
||||
break;
|
||||
}
|
||||
if(k == n)
|
||||
newarray->slot[i++] = slot;
|
||||
}
|
||||
|
||||
newarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray,
|
||||
almemory_order_acq_rel);
|
||||
device = context->Device;
|
||||
while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
|
||||
althrd_yield();
|
||||
al_free(newarray);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
DeinitEffectSlot(slot);
|
||||
|
||||
@@ -203,7 +205,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *
|
||||
}
|
||||
|
||||
done:
|
||||
UnlockEffectSlotsWrite(context);
|
||||
UnlockEffectSlotList(context);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@@ -215,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);
|
||||
|
||||
@@ -235,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);
|
||||
}
|
||||
|
||||
@@ -290,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);
|
||||
}
|
||||
|
||||
@@ -312,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);
|
||||
}
|
||||
|
||||
@@ -349,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);
|
||||
}
|
||||
|
||||
@@ -371,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:
|
||||
@@ -381,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);
|
||||
}
|
||||
|
||||
@@ -404,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);
|
||||
}
|
||||
|
||||
@@ -426,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:
|
||||
@@ -436,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);
|
||||
}
|
||||
|
||||
@@ -458,54 +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);
|
||||
}
|
||||
|
||||
|
||||
void InitEffectFactoryMap(void)
|
||||
{
|
||||
InitUIntMap(&EffectStateFactoryMap, INT_MAX);
|
||||
|
||||
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;
|
||||
EffectStateFactory *factory;
|
||||
|
||||
factory = getFactoryByType(newtype);
|
||||
if(!factory)
|
||||
@@ -513,7 +499,7 @@ 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;
|
||||
|
||||
START_MIXER_MODE();
|
||||
@@ -548,7 +534,7 @@ 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_SEQ(&EffectSlot->FreeList);
|
||||
props = ATOMIC_LOAD_SEQ(&Context->FreeEffectslotProps);
|
||||
while(props)
|
||||
{
|
||||
if(props->State)
|
||||
@@ -568,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);
|
||||
@@ -590,15 +576,103 @@ 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->Gain = 1.0;
|
||||
slot->AuxSendAuto = AL_TRUE;
|
||||
@@ -606,7 +680,6 @@ ALenum InitEffectSlot(ALeffectslot *slot)
|
||||
InitRef(&slot->ref, 0);
|
||||
|
||||
ATOMIC_INIT(&slot->Update, NULL);
|
||||
ATOMIC_INIT(&slot->FreeList, NULL);
|
||||
|
||||
slot->Params.Gain = 1.0f;
|
||||
slot->Params.AuxSendAuto = AL_TRUE;
|
||||
@@ -614,6 +687,7 @@ 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;
|
||||
@@ -624,7 +698,6 @@ ALenum InitEffectSlot(ALeffectslot *slot)
|
||||
void DeinitEffectSlot(ALeffectslot *slot)
|
||||
{
|
||||
struct ALeffectslotProps *props;
|
||||
size_t count = 0;
|
||||
|
||||
props = ATOMIC_LOAD_SEQ(&slot->Update);
|
||||
if(props)
|
||||
@@ -633,29 +706,19 @@ void DeinitEffectSlot(ALeffectslot *slot)
|
||||
TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
|
||||
al_free(props);
|
||||
}
|
||||
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
|
||||
while(props)
|
||||
{
|
||||
struct ALeffectslotProps *next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
|
||||
if(props->State) ALeffectState_DecRef(props->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
|
||||
@@ -663,7 +726,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot)
|
||||
struct ALeffectslotProps *next;
|
||||
do {
|
||||
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
|
||||
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&slot->FreeList, &props, next,
|
||||
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeEffectslotProps, &props, next,
|
||||
almemory_order_seq_cst, almemory_order_acquire) == 0);
|
||||
}
|
||||
|
||||
@@ -687,7 +750,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot)
|
||||
/* If there was an unused update container, put it back in the
|
||||
* freelist.
|
||||
*/
|
||||
ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &slot->FreeList, props);
|
||||
ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props);
|
||||
}
|
||||
|
||||
if(oldstate)
|
||||
@@ -699,29 +762,35 @@ void UpdateAllEffectSlotProps(ALCcontext *context)
|
||||
struct ALeffectslotArray *auxslots;
|
||||
ALsizei i;
|
||||
|
||||
LockEffectSlotsRead(context);
|
||||
LockEffectSlotList(context);
|
||||
auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire);
|
||||
for(i = 0;i < auxslots->count;i++)
|
||||
{
|
||||
ALeffectslot *slot = auxslots->slot[i];
|
||||
if(!ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel))
|
||||
UpdateEffectSlotProps(slot);
|
||||
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
@@ -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[AL__EAXREVERB])
|
||||
if(!DisabledEffects[EAXREVERB_EFFECT])
|
||||
InitEffectParams(effect, AL_EFFECT_EAXREVERB);
|
||||
else if(!DisabledEffects[AL__REVERB])
|
||||
else if(!DisabledEffects[REVERB_EFFECT])
|
||||
InitEffectParams(effect, AL_EFFECT_REVERB);
|
||||
else
|
||||
InitEffectParams(effect, AL_EFFECT_NULL);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@@ -33,11 +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;
|
||||
|
||||
WARN("Error generated on context %p, code 0x%04x\n", Context, errorCode);
|
||||
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
|
||||
@@ -49,19 +71,29 @@ ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
|
||||
#endif
|
||||
}
|
||||
|
||||
(void)(ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&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)
|
||||
{
|
||||
WARN("Querying error state on null context (implicitly 0x%04x)\n",
|
||||
AL_INVALID_OPERATION);
|
||||
const ALenum deferror = AL_INVALID_OPERATION;
|
||||
WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror);
|
||||
if(TrapALError)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -71,12 +103,11 @@ AL_API ALenum AL_APIENTRY alGetError(void)
|
||||
raise(SIGTRAP);
|
||||
#endif
|
||||
}
|
||||
return AL_INVALID_OPERATION;
|
||||
return deferror;
|
||||
}
|
||||
|
||||
errorCode = ATOMIC_EXCHANGE_SEQ(&Context->LastError, AL_NO_ERROR);
|
||||
|
||||
ALCcontext_DecRef(Context);
|
||||
errorCode = ATOMIC_EXCHANGE_SEQ(&context->LastError, AL_NO_ERROR);
|
||||
|
||||
ALCcontext_DecRef(context);
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
@@ -35,22 +35,6 @@
|
||||
#include "AL/alc.h"
|
||||
|
||||
|
||||
const struct EffectList EffectList[] = {
|
||||
{ "eaxreverb", AL__EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB },
|
||||
{ "reverb", AL__REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB },
|
||||
{ "chorus", AL__CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS },
|
||||
{ "compressor", AL__COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR },
|
||||
{ "distortion", AL__DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION },
|
||||
{ "echo", AL__ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO },
|
||||
{ "equalizer", AL__EQUALIZER, "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER },
|
||||
{ "flanger", AL__FLANGER, "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER },
|
||||
{ "modulator", AL__MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR },
|
||||
{ "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
|
||||
{ "dedicated", AL__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;
|
||||
|
||||
@@ -25,66 +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_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src);
|
||||
extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei 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);
|
||||
}
|
||||
|
||||
@@ -99,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);
|
||||
}
|
||||
|
||||
@@ -130,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);
|
||||
|
||||
@@ -150,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)
|
||||
@@ -161,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);
|
||||
}
|
||||
@@ -191,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);
|
||||
}
|
||||
@@ -214,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);
|
||||
}
|
||||
@@ -237,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);
|
||||
}
|
||||
@@ -260,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)
|
||||
@@ -270,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);
|
||||
}
|
||||
@@ -295,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);
|
||||
}
|
||||
@@ -318,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);
|
||||
}
|
||||
@@ -341,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
|
||||
assert(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)
|
||||
{
|
||||
@@ -481,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)
|
||||
{
|
||||
@@ -536,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)
|
||||
{
|
||||
@@ -601,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");
|
||||
}
|
||||
|
||||
|
||||
@@ -654,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)
|
||||
{
|
||||
@@ -671,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)
|
||||
{
|
||||
@@ -688,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
|
||||
{
|
||||
@@ -705,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;
|
||||
}
|
||||
|
||||
@@ -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,7 +468,7 @@ void UpdateListenerProps(ALCcontext *context)
|
||||
struct ALlistenerProps *next;
|
||||
do {
|
||||
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
|
||||
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&listener->FreeList, &props, next,
|
||||
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeListenerProps, &props, next,
|
||||
almemory_order_seq_cst, almemory_order_acquire) == 0);
|
||||
}
|
||||
|
||||
@@ -489,14 +489,6 @@ void UpdateListenerProps(ALCcontext *context)
|
||||
props->Up[2] = listener->Up[2];
|
||||
|
||||
props->Gain = listener->Gain;
|
||||
props->MetersPerUnit = listener->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(&listener->Update, props, almemory_order_acq_rel);
|
||||
@@ -505,6 +497,6 @@ void UpdateListenerProps(ALCcontext *context)
|
||||
/* If there was an unused update container, put it back in the
|
||||
* freelist.
|
||||
*/
|
||||
ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &listener->FreeList, props);
|
||||
ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &context->FreeListenerProps, props);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,8 +50,27 @@ static const ALchar alErrOutOfMemory[] = "Out of Memory";
|
||||
/* Resampler strings */
|
||||
static const ALchar alPointResampler[] = "Nearest";
|
||||
static const ALchar alLinearResampler[] = "Linear";
|
||||
static const ALchar alSinc4Resampler[] = "4-Point Sinc";
|
||||
static const ALchar alBSincResampler[] = "Band-limited Sinc (12/24)";
|
||||
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)
|
||||
{
|
||||
@@ -60,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);
|
||||
}
|
||||
|
||||
@@ -85,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);
|
||||
}
|
||||
|
||||
@@ -111,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:
|
||||
@@ -118,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;
|
||||
}
|
||||
|
||||
@@ -135,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:
|
||||
@@ -177,12 +193,11 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -194,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:
|
||||
@@ -230,12 +246,11 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -247,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:
|
||||
@@ -283,12 +299,11 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -300,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:
|
||||
@@ -336,12 +352,11 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -353,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:
|
||||
@@ -389,12 +405,39 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -422,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);
|
||||
}
|
||||
|
||||
@@ -458,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);
|
||||
}
|
||||
|
||||
@@ -494,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);
|
||||
}
|
||||
|
||||
@@ -530,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);
|
||||
}
|
||||
|
||||
@@ -564,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);
|
||||
}
|
||||
|
||||
@@ -625,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;
|
||||
}
|
||||
|
||||
@@ -642,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);
|
||||
}
|
||||
|
||||
@@ -661,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);
|
||||
}
|
||||
|
||||
@@ -682,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);
|
||||
}
|
||||
|
||||
@@ -705,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);
|
||||
}
|
||||
|
||||
@@ -750,7 +831,8 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
|
||||
{
|
||||
const char *ResamplerNames[] = {
|
||||
alPointResampler, alLinearResampler,
|
||||
alSinc4Resampler, alBSincResampler,
|
||||
alCubicResampler, alBSinc12Resampler,
|
||||
alBSinc24Resampler,
|
||||
};
|
||||
const ALchar *value = NULL;
|
||||
ALCcontext *context;
|
||||
@@ -764,16 +846,55 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
|
||||
{
|
||||
case AL_RESAMPLER_NAME_SOFT:
|
||||
if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Resampler name index %d out of range",
|
||||
index);
|
||||
value = ResamplerNames[index];
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,108 +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_FLAG *ThunkArray;
|
||||
static ALsizei 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;
|
||||
ALsizei i;
|
||||
|
||||
ReadLock(&ThunkLock);
|
||||
for(i = 0;i < ThunkArraySize;i++)
|
||||
{
|
||||
if(!ATOMIC_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_acq_rel))
|
||||
{
|
||||
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_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_acq_rel))
|
||||
{
|
||||
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_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_seq_cst);
|
||||
*index = ++i;
|
||||
|
||||
for(;i < ThunkArraySize;i++)
|
||||
ATOMIC_FLAG_CLEAR(&ThunkArray[i], almemory_order_relaxed);
|
||||
WriteUnlock(&ThunkLock);
|
||||
|
||||
return AL_NO_ERROR;
|
||||
}
|
||||
|
||||
void FreeThunkEntry(ALuint index)
|
||||
{
|
||||
ReadLock(&ThunkLock);
|
||||
if(index > 0 && (ALsizei)index <= ThunkArraySize)
|
||||
ATOMIC_FLAG_CLEAR(&ThunkArray[index-1], almemory_order_release);
|
||||
ReadUnlock(&ThunkLock);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -3,13 +3,6 @@
|
||||
|
||||
#include "sample_cvt.h"
|
||||
|
||||
#ifdef HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "alu.h"
|
||||
#include "alBuffer.h"
|
||||
@@ -61,7 +54,7 @@ static const int MSADPCMAdaptionCoeff[7][2] = {
|
||||
|
||||
/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a
|
||||
* signed 16-bit sample */
|
||||
static const ALshort muLawDecompressionTable[256] = {
|
||||
const ALshort muLawDecompressionTable[256] = {
|
||||
-32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
|
||||
-23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
|
||||
-15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
|
||||
@@ -96,32 +89,10 @@ static const ALshort muLawDecompressionTable[256] = {
|
||||
56, 48, 40, 32, 24, 16, 8, 0
|
||||
};
|
||||
|
||||
/* Values used when encoding a muLaw sample */
|
||||
static const int muLawBias = 0x84;
|
||||
static const int muLawClip = 32635;
|
||||
static const char muLawCompressTable[256] = {
|
||||
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
|
||||
};
|
||||
|
||||
|
||||
/* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a
|
||||
* signed 16-bit sample */
|
||||
static const ALshort aLawDecompressionTable[256] = {
|
||||
const ALshort aLawDecompressionTable[256] = {
|
||||
-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
|
||||
-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
|
||||
-2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
|
||||
@@ -156,84 +127,13 @@ static const ALshort aLawDecompressionTable[256] = {
|
||||
944, 912, 1008, 976, 816, 784, 880, 848
|
||||
};
|
||||
|
||||
/* Values used when encoding an aLaw sample */
|
||||
static const int aLawClip = 32635;
|
||||
static const char aLawCompressTable[128] = {
|
||||
1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,
|
||||
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
|
||||
};
|
||||
|
||||
|
||||
typedef ALubyte ALmulaw;
|
||||
typedef ALubyte ALalaw;
|
||||
typedef ALubyte ALima4;
|
||||
typedef ALubyte ALmsadpcm;
|
||||
|
||||
static inline ALshort DecodeMuLaw(ALmulaw val)
|
||||
{ return muLawDecompressionTable[val]; }
|
||||
|
||||
static ALmulaw EncodeMuLaw(ALshort val)
|
||||
static void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align)
|
||||
{
|
||||
ALint mant, exp, sign;
|
||||
|
||||
sign = (val>>8) & 0x80;
|
||||
if(sign)
|
||||
{
|
||||
/* -32768 doesn't properly negate on a short; it results in itself.
|
||||
* So clamp to -32767 */
|
||||
val = maxi(val, -32767);
|
||||
val = -val;
|
||||
}
|
||||
|
||||
val = mini(val, muLawClip);
|
||||
val += muLawBias;
|
||||
|
||||
exp = muLawCompressTable[(val>>7) & 0xff];
|
||||
mant = (val >> (exp+3)) & 0x0f;
|
||||
|
||||
return ~(sign | (exp<<4) | mant);
|
||||
}
|
||||
|
||||
static inline ALshort DecodeALaw(ALalaw val)
|
||||
{ return aLawDecompressionTable[val]; }
|
||||
|
||||
static ALalaw EncodeALaw(ALshort val)
|
||||
{
|
||||
ALint mant, exp, sign;
|
||||
|
||||
sign = ((~val) >> 8) & 0x80;
|
||||
if(!sign)
|
||||
{
|
||||
val = maxi(val, -32767);
|
||||
val = -val;
|
||||
}
|
||||
val = mini(val, aLawClip);
|
||||
|
||||
if(val >= 256)
|
||||
{
|
||||
exp = aLawCompressTable[(val>>8) & 0x7f];
|
||||
mant = (val >> (exp+3)) & 0x0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
exp = 0;
|
||||
mant = val >> 4;
|
||||
}
|
||||
|
||||
return ((exp<<4) | mant) ^ (sign^0x55);
|
||||
}
|
||||
|
||||
static void DecodeIMA4Block(ALshort *dst, const ALima4 *src, ALint numchans, ALsizei align)
|
||||
{
|
||||
ALint sample[MAX_INPUT_CHANNELS], index[MAX_INPUT_CHANNELS];
|
||||
ALuint code[MAX_INPUT_CHANNELS];
|
||||
ALsizei j,k,c;
|
||||
ALint sample[MAX_INPUT_CHANNELS] = { 0 };
|
||||
ALint index[MAX_INPUT_CHANNELS] = { 0 };
|
||||
ALuint code[MAX_INPUT_CHANNELS] = { 0 };
|
||||
ALsizei c, i;
|
||||
|
||||
for(c = 0;c < numchans;c++)
|
||||
{
|
||||
@@ -249,143 +149,77 @@ static void DecodeIMA4Block(ALshort *dst, const ALima4 *src, ALint numchans, ALs
|
||||
dst[c] = sample[c];
|
||||
}
|
||||
|
||||
for(j = 1;j < align;j += 8)
|
||||
for(i = 1;i < align;i++)
|
||||
{
|
||||
for(c = 0;c < numchans;c++)
|
||||
{
|
||||
code[c] = *(src++);
|
||||
code[c] |= *(src++) << 8;
|
||||
code[c] |= *(src++) << 16;
|
||||
code[c] |= *(src++) << 24;
|
||||
}
|
||||
|
||||
for(k = 0;k < 8;k++)
|
||||
if((i&7) == 1)
|
||||
{
|
||||
for(c = 0;c < numchans;c++)
|
||||
{
|
||||
int nibble = code[c]&0xf;
|
||||
code[c] >>= 4;
|
||||
|
||||
sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8;
|
||||
sample[c] = clampi(sample[c], -32768, 32767);
|
||||
|
||||
index[c] += IMA4Index_adjust[nibble];
|
||||
index[c] = clampi(index[c], 0, 88);
|
||||
|
||||
dst[(j+k)*numchans + c] = sample[c];
|
||||
code[c] = *(src++);
|
||||
code[c] |= *(src++) << 8;
|
||||
code[c] |= *(src++) << 16;
|
||||
code[c] |= *(src++) << 24;
|
||||
}
|
||||
}
|
||||
|
||||
for(c = 0;c < numchans;c++)
|
||||
{
|
||||
int nibble = code[c]&0xf;
|
||||
code[c] >>= 4;
|
||||
|
||||
sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8;
|
||||
sample[c] = clampi(sample[c], -32768, 32767);
|
||||
|
||||
index[c] += IMA4Index_adjust[nibble];
|
||||
index[c] = clampi(index[c], 0, 88);
|
||||
|
||||
*(dst++) = sample[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void EncodeIMA4Block(ALima4 *dst, const ALshort *src, ALint *sample, ALint *index, ALint numchans, ALsizei align)
|
||||
static void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align)
|
||||
{
|
||||
ALsizei j,k,c;
|
||||
ALubyte blockpred[MAX_INPUT_CHANNELS] = { 0 };
|
||||
ALint delta[MAX_INPUT_CHANNELS] = { 0 };
|
||||
ALshort samples[MAX_INPUT_CHANNELS][2] = { { 0, 0 } };
|
||||
ALint c, i;
|
||||
|
||||
for(c = 0;c < numchans;c++)
|
||||
{
|
||||
int diff = src[c] - sample[c];
|
||||
int step = IMAStep_size[index[c]];
|
||||
int nibble;
|
||||
|
||||
nibble = 0;
|
||||
if(diff < 0)
|
||||
{
|
||||
nibble = 0x8;
|
||||
diff = -diff;
|
||||
}
|
||||
|
||||
diff = mini(step*2, diff);
|
||||
nibble |= (diff*8/step - 1) / 2;
|
||||
|
||||
sample[c] += IMA4Codeword[nibble] * step / 8;
|
||||
sample[c] = clampi(sample[c], -32768, 32767);
|
||||
|
||||
index[c] += IMA4Index_adjust[nibble];
|
||||
index[c] = clampi(index[c], 0, 88);
|
||||
|
||||
*(dst++) = sample[c] & 0xff;
|
||||
*(dst++) = (sample[c]>>8) & 0xff;
|
||||
*(dst++) = index[c] & 0xff;
|
||||
*(dst++) = (index[c]>>8) & 0xff;
|
||||
blockpred[c] = *(src++);
|
||||
blockpred[c] = minu(blockpred[c], 6);
|
||||
}
|
||||
|
||||
for(j = 1;j < align;j += 8)
|
||||
for(c = 0;c < numchans;c++)
|
||||
{
|
||||
for(c = 0;c < numchans;c++)
|
||||
{
|
||||
for(k = 0;k < 8;k++)
|
||||
{
|
||||
int diff = src[(j+k)*numchans + c] - sample[c];
|
||||
int step = IMAStep_size[index[c]];
|
||||
int nibble;
|
||||
|
||||
nibble = 0;
|
||||
if(diff < 0)
|
||||
{
|
||||
nibble = 0x8;
|
||||
diff = -diff;
|
||||
}
|
||||
|
||||
diff = mini(step*2, diff);
|
||||
nibble |= (diff*8/step - 1) / 2;
|
||||
|
||||
sample[c] += IMA4Codeword[nibble] * step / 8;
|
||||
sample[c] = clampi(sample[c], -32768, 32767);
|
||||
|
||||
index[c] += IMA4Index_adjust[nibble];
|
||||
index[c] = clampi(index[c], 0, 88);
|
||||
|
||||
if(!(k&1)) *dst = nibble;
|
||||
else *(dst++) |= nibble<<4;
|
||||
}
|
||||
}
|
||||
delta[c] = *(src++);
|
||||
delta[c] |= *(src++) << 8;
|
||||
delta[c] = (delta[c]^0x8000) - 32768;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void DecodeMSADPCMBlock(ALshort *dst, const ALmsadpcm *src, ALint numchans, ALsizei align)
|
||||
{
|
||||
ALubyte blockpred[MAX_INPUT_CHANNELS];
|
||||
ALint delta[MAX_INPUT_CHANNELS];
|
||||
ALshort samples[MAX_INPUT_CHANNELS][2];
|
||||
ALint i, j;
|
||||
|
||||
for(i = 0;i < numchans;i++)
|
||||
for(c = 0;c < numchans;c++)
|
||||
{
|
||||
blockpred[i] = *(src++);
|
||||
blockpred[i] = minu(blockpred[i], 6);
|
||||
samples[c][0] = *(src++);
|
||||
samples[c][0] |= *(src++) << 8;
|
||||
samples[c][0] = (samples[c][0]^0x8000) - 32768;
|
||||
}
|
||||
for(i = 0;i < numchans;i++)
|
||||
for(c = 0;c < numchans;c++)
|
||||
{
|
||||
delta[i] = *(src++);
|
||||
delta[i] |= *(src++) << 8;
|
||||
delta[i] = (delta[i]^0x8000) - 0x8000;
|
||||
}
|
||||
for(i = 0;i < numchans;i++)
|
||||
{
|
||||
samples[i][0] = *(src++);
|
||||
samples[i][0] |= *(src++) << 8;
|
||||
samples[i][0] = (samples[i][0]^0x8000) - 0x8000;
|
||||
}
|
||||
for(i = 0;i < numchans;i++)
|
||||
{
|
||||
samples[i][1] = *(src++);
|
||||
samples[i][1] |= *(src++) << 8;
|
||||
samples[i][1] = (samples[i][1]^0x8000) - 0x8000;
|
||||
samples[c][1] = *(src++);
|
||||
samples[c][1] |= *(src++) << 8;
|
||||
samples[c][1] = (samples[c][1]^0x8000) - 0x8000;
|
||||
}
|
||||
|
||||
/* Second sample is written first. */
|
||||
for(i = 0;i < numchans;i++)
|
||||
*(dst++) = samples[i][1];
|
||||
for(i = 0;i < numchans;i++)
|
||||
*(dst++) = samples[i][0];
|
||||
for(c = 0;c < numchans;c++)
|
||||
*(dst++) = samples[c][1];
|
||||
for(c = 0;c < numchans;c++)
|
||||
*(dst++) = samples[c][0];
|
||||
|
||||
for(j = 2;j < align;j++)
|
||||
for(i = 2;i < align;i++)
|
||||
{
|
||||
for(i = 0;i < numchans;i++)
|
||||
for(c = 0;c < numchans;c++)
|
||||
{
|
||||
const ALint num = (j*numchans) + i;
|
||||
const ALint num = (i*numchans) + c;
|
||||
ALint nibble, pred;
|
||||
|
||||
/* Read the nibble (first is in the upper bits). */
|
||||
@@ -394,310 +228,28 @@ static void DecodeMSADPCMBlock(ALshort *dst, const ALmsadpcm *src, ALint numchan
|
||||
else
|
||||
nibble = (*(src++))&0x0f;
|
||||
|
||||
pred = (samples[i][0]*MSADPCMAdaptionCoeff[blockpred[i]][0] +
|
||||
samples[i][1]*MSADPCMAdaptionCoeff[blockpred[i]][1]) / 256;
|
||||
pred += ((nibble^0x08) - 0x08) * delta[i];
|
||||
pred = (samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] +
|
||||
samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256;
|
||||
pred += ((nibble^0x08) - 0x08) * delta[c];
|
||||
pred = clampi(pred, -32768, 32767);
|
||||
|
||||
samples[i][1] = samples[i][0];
|
||||
samples[i][0] = pred;
|
||||
samples[c][1] = samples[c][0];
|
||||
samples[c][0] = pred;
|
||||
|
||||
delta[i] = (MSADPCMAdaption[nibble] * delta[i]) / 256;
|
||||
delta[i] = maxi(16, delta[i]);
|
||||
delta[c] = (MSADPCMAdaption[nibble] * delta[c]) / 256;
|
||||
delta[c] = maxi(16, delta[c]);
|
||||
|
||||
*(dst++) = pred;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: This encoder is pretty dumb/simplistic. Some kind of pre-processing
|
||||
* that tries to find the optimal block predictors would be nice, at least. A
|
||||
* multi-pass method that can generate better deltas would be good, too. */
|
||||
static void EncodeMSADPCMBlock(ALmsadpcm *dst, const ALshort *src, ALint *sample, ALint numchans, ALsizei align)
|
||||
{
|
||||
ALubyte blockpred[MAX_INPUT_CHANNELS];
|
||||
ALint delta[MAX_INPUT_CHANNELS];
|
||||
ALshort samples[MAX_INPUT_CHANNELS][2];
|
||||
ALint i, j;
|
||||
|
||||
/* Block predictor */
|
||||
for(i = 0;i < numchans;i++)
|
||||
{
|
||||
/* FIXME: Calculate something better. */
|
||||
blockpred[i] = 0;
|
||||
*(dst++) = blockpred[i];
|
||||
}
|
||||
/* Initial delta */
|
||||
for(i = 0;i < numchans;i++)
|
||||
{
|
||||
delta[i] = 16;
|
||||
*(dst++) = (delta[i] ) & 0xff;
|
||||
*(dst++) = (delta[i]>>8) & 0xff;
|
||||
}
|
||||
/* Initial sample 1 */
|
||||
for(i = 0;i < numchans;i++)
|
||||
{
|
||||
samples[i][0] = src[1*numchans + i];
|
||||
*(dst++) = (samples[i][0] ) & 0xff;
|
||||
*(dst++) = (samples[i][0]>>8) & 0xff;
|
||||
}
|
||||
/* Initial sample 2 */
|
||||
for(i = 0;i < numchans;i++)
|
||||
{
|
||||
samples[i][1] = src[i];
|
||||
*(dst++) = (samples[i][1] ) & 0xff;
|
||||
*(dst++) = (samples[i][1]>>8) & 0xff;
|
||||
}
|
||||
|
||||
for(j = 2;j < align;j++)
|
||||
{
|
||||
for(i = 0;i < numchans;i++)
|
||||
{
|
||||
const ALint num = (j*numchans) + i;
|
||||
ALint nibble = 0;
|
||||
ALint bias;
|
||||
|
||||
sample[i] = (samples[i][0]*MSADPCMAdaptionCoeff[blockpred[i]][0] +
|
||||
samples[i][1]*MSADPCMAdaptionCoeff[blockpred[i]][1]) / 256;
|
||||
|
||||
nibble = src[num] - sample[i];
|
||||
if(nibble >= 0)
|
||||
bias = delta[i] / 2;
|
||||
else
|
||||
bias = -delta[i] / 2;
|
||||
|
||||
nibble = (nibble + bias) / delta[i];
|
||||
nibble = clampi(nibble, -8, 7)&0x0f;
|
||||
|
||||
sample[i] += ((nibble^0x08)-0x08) * delta[i];
|
||||
sample[i] = clampi(sample[i], -32768, 32767);
|
||||
|
||||
samples[i][1] = samples[i][0];
|
||||
samples[i][0] = sample[i];
|
||||
|
||||
delta[i] = (MSADPCMAdaption[nibble] * delta[i]) / 256;
|
||||
delta[i] = maxi(16, delta[i]);
|
||||
|
||||
if(!(num&1))
|
||||
*dst = nibble << 4;
|
||||
else
|
||||
{
|
||||
*dst |= nibble;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Define same-type pass-through sample conversion functions (excludes ADPCM,
|
||||
* which are block-based). */
|
||||
#define DECL_TEMPLATE(T) \
|
||||
static inline T Conv_##T##_##T(T val) { return val; }
|
||||
|
||||
DECL_TEMPLATE(ALbyte);
|
||||
DECL_TEMPLATE(ALubyte);
|
||||
DECL_TEMPLATE(ALshort);
|
||||
DECL_TEMPLATE(ALushort);
|
||||
DECL_TEMPLATE(ALint);
|
||||
DECL_TEMPLATE(ALuint);
|
||||
DECL_TEMPLATE(ALalaw);
|
||||
DECL_TEMPLATE(ALmulaw);
|
||||
|
||||
/* Slightly special handling for floats and doubles (converts NaN to 0, and
|
||||
* allows float<->double pass-through).
|
||||
*/
|
||||
static inline ALfloat Conv_ALfloat_ALfloat(ALfloat val)
|
||||
{ return (val==val) ? val : 0.0f; }
|
||||
static inline ALfloat Conv_ALfloat_ALdouble(ALdouble val)
|
||||
{ return (val==val) ? (ALfloat)val : 0.0f; }
|
||||
static inline ALdouble Conv_ALdouble_ALfloat(ALfloat val)
|
||||
{ return (val==val) ? (ALdouble)val : 0.0; }
|
||||
static inline ALdouble Conv_ALdouble_ALdouble(ALdouble val)
|
||||
{ return (val==val) ? val : 0.0; }
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
/* Define alternate-sign functions. */
|
||||
#define DECL_TEMPLATE(T1, T2, O) \
|
||||
static inline T1 Conv_##T1##_##T2(T2 val) { return (T1)val - O; } \
|
||||
static inline T2 Conv_##T2##_##T1(T1 val) { return (T2)val + O; }
|
||||
|
||||
DECL_TEMPLATE(ALbyte, ALubyte, 128);
|
||||
DECL_TEMPLATE(ALshort, ALushort, 32768);
|
||||
DECL_TEMPLATE(ALint, ALuint, 2147483648u);
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
/* Define int-type to int-type functions */
|
||||
#define DECL_TEMPLATE(T, ST, UT, SH) \
|
||||
static inline T Conv_##T##_##ST(ST val){ return val >> SH; } \
|
||||
static inline T Conv_##T##_##UT(UT val){ return Conv_##ST##_##UT(val) >> SH; }\
|
||||
static inline ST Conv_##ST##_##T(T val){ return val << SH; } \
|
||||
static inline UT Conv_##UT##_##T(T val){ return Conv_##UT##_##ST(val << SH); }
|
||||
|
||||
#define DECL_TEMPLATE2(T1, T2, SH) \
|
||||
DECL_TEMPLATE(AL##T1, AL##T2, ALu##T2, SH) \
|
||||
DECL_TEMPLATE(ALu##T1, ALu##T2, AL##T2, SH)
|
||||
|
||||
DECL_TEMPLATE2(byte, short, 8)
|
||||
DECL_TEMPLATE2(short, int, 16)
|
||||
DECL_TEMPLATE2(byte, int, 24)
|
||||
|
||||
#undef DECL_TEMPLATE2
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
/* Define int-type to fp functions */
|
||||
#define DECL_TEMPLATE(T, ST, UT, OP) \
|
||||
static inline T Conv_##T##_##ST(ST val) { return (T)val * OP; } \
|
||||
static inline T Conv_##T##_##UT(UT val) { return (T)Conv_##ST##_##UT(val) * OP; }
|
||||
|
||||
#define DECL_TEMPLATE2(T1, T2, OP) \
|
||||
DECL_TEMPLATE(T1, AL##T2, ALu##T2, OP)
|
||||
|
||||
DECL_TEMPLATE2(ALfloat, byte, (1.0f/128.0f))
|
||||
DECL_TEMPLATE2(ALdouble, byte, (1.0/128.0))
|
||||
DECL_TEMPLATE2(ALfloat, short, (1.0f/32768.0f))
|
||||
DECL_TEMPLATE2(ALdouble, short, (1.0/32768.0))
|
||||
DECL_TEMPLATE2(ALdouble, int, (1.0/2147483648.0))
|
||||
|
||||
/* Special handling for int32 to float32, since it would overflow. */
|
||||
static inline ALfloat Conv_ALfloat_ALint(ALint val)
|
||||
{ return (ALfloat)(val>>7) * (1.0f/16777216.0f); }
|
||||
static inline ALfloat Conv_ALfloat_ALuint(ALuint val)
|
||||
{ return (ALfloat)(Conv_ALint_ALuint(val)>>7) * (1.0f/16777216.0f); }
|
||||
|
||||
#undef DECL_TEMPLATE2
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
/* Define fp to int-type functions */
|
||||
#define DECL_TEMPLATE(FT, T, smin, smax) \
|
||||
static inline AL##T Conv_AL##T##_##FT(FT val) \
|
||||
{ \
|
||||
val *= (FT)smax + 1; \
|
||||
if(val >= (FT)smax) return smax; \
|
||||
if(val <= (FT)smin) return smin; \
|
||||
return (AL##T)val; \
|
||||
} \
|
||||
static inline ALu##T Conv_ALu##T##_##FT(FT val) \
|
||||
{ return Conv_ALu##T##_AL##T(Conv_AL##T##_##FT(val)); }
|
||||
|
||||
DECL_TEMPLATE(ALfloat, byte, -128, 127)
|
||||
DECL_TEMPLATE(ALdouble, byte, -128, 127)
|
||||
DECL_TEMPLATE(ALfloat, short, -32768, 32767)
|
||||
DECL_TEMPLATE(ALdouble, short, -32768, 32767)
|
||||
DECL_TEMPLATE(ALdouble, int, -2147483647-1, 2147483647)
|
||||
|
||||
/* Special handling for float32 to int32, since it would overflow. */
|
||||
static inline ALint Conv_ALint_ALfloat(ALfloat val)
|
||||
{
|
||||
val *= 16777216.0f;
|
||||
if(val >= 16777215.0f) return 0x7fffff80/*16777215 << 7*/;
|
||||
if(val <= -16777216.0f) return 0x80000000/*-16777216 << 7*/;
|
||||
return (ALint)val << 7;
|
||||
}
|
||||
static inline ALuint Conv_ALuint_ALfloat(ALfloat val)
|
||||
{ return Conv_ALuint_ALint(Conv_ALint_ALfloat(val)); }
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
/* Define muLaw and aLaw functions (goes through short functions). */
|
||||
#define DECL_TEMPLATE(T) \
|
||||
static inline ALmulaw Conv_ALmulaw_##T(T val) \
|
||||
{ return EncodeMuLaw(Conv_ALshort_##T(val)); } \
|
||||
static inline T Conv_##T##_ALmulaw(ALmulaw val) \
|
||||
{ return Conv_##T##_ALshort(DecodeMuLaw(val)); } \
|
||||
\
|
||||
static inline ALalaw Conv_ALalaw_##T(T val) \
|
||||
{ return EncodeALaw(Conv_ALshort_##T(val)); } \
|
||||
static inline T Conv_##T##_ALalaw(ALalaw val) \
|
||||
{ return Conv_##T##_ALshort(DecodeALaw(val)); }
|
||||
|
||||
DECL_TEMPLATE(ALbyte)
|
||||
DECL_TEMPLATE(ALubyte)
|
||||
DECL_TEMPLATE(ALshort)
|
||||
DECL_TEMPLATE(ALushort)
|
||||
DECL_TEMPLATE(ALint)
|
||||
DECL_TEMPLATE(ALuint)
|
||||
DECL_TEMPLATE(ALfloat)
|
||||
DECL_TEMPLATE(ALdouble)
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
/* Define muLaw <-> aLaw functions. */
|
||||
static inline ALalaw Conv_ALalaw_ALmulaw(ALmulaw val)
|
||||
{ return EncodeALaw(DecodeMuLaw(val)); }
|
||||
static inline ALmulaw Conv_ALmulaw_ALalaw(ALalaw val)
|
||||
{ return EncodeMuLaw(DecodeALaw(val)); }
|
||||
|
||||
|
||||
#define DECL_TEMPLATE(T1, T2) \
|
||||
static void Convert_##T1##_##T2(T1 *dst, const T2 *src, ALuint numchans, \
|
||||
ALuint len, ALsizei UNUSED(align)) \
|
||||
{ \
|
||||
ALuint i, j; \
|
||||
for(i = 0;i < len;i++) \
|
||||
{ \
|
||||
for(j = 0;j < numchans;j++) \
|
||||
*(dst++) = Conv_##T1##_##T2(*(src++)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DECL_TEMPLATE2(T) \
|
||||
DECL_TEMPLATE(T, ALbyte) \
|
||||
DECL_TEMPLATE(T, ALubyte) \
|
||||
DECL_TEMPLATE(T, ALshort) \
|
||||
DECL_TEMPLATE(T, ALushort) \
|
||||
DECL_TEMPLATE(T, ALint) \
|
||||
DECL_TEMPLATE(T, ALuint) \
|
||||
DECL_TEMPLATE(T, ALfloat) \
|
||||
DECL_TEMPLATE(T, ALdouble) \
|
||||
DECL_TEMPLATE(T, ALmulaw) \
|
||||
DECL_TEMPLATE(T, ALalaw)
|
||||
|
||||
DECL_TEMPLATE2(ALbyte)
|
||||
DECL_TEMPLATE2(ALubyte)
|
||||
DECL_TEMPLATE2(ALshort)
|
||||
DECL_TEMPLATE2(ALushort)
|
||||
DECL_TEMPLATE2(ALint)
|
||||
DECL_TEMPLATE2(ALuint)
|
||||
DECL_TEMPLATE2(ALfloat)
|
||||
DECL_TEMPLATE2(ALdouble)
|
||||
DECL_TEMPLATE2(ALmulaw)
|
||||
DECL_TEMPLATE2(ALalaw)
|
||||
|
||||
#undef DECL_TEMPLATE2
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
#define DECL_TEMPLATE(T) \
|
||||
static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALuint numchans, \
|
||||
ALuint len, ALuint align) \
|
||||
{ \
|
||||
ALsizei byte_align = ((align-1)/2 + 4) * numchans; \
|
||||
DECL_VLA(ALshort, tmp, align*numchans); \
|
||||
ALuint i, j, k; \
|
||||
\
|
||||
assert(align > 0 && (len%align) == 0); \
|
||||
for(i = 0;i < len;i += align) \
|
||||
{ \
|
||||
DecodeIMA4Block(tmp, src, numchans, align); \
|
||||
src += byte_align; \
|
||||
\
|
||||
for(j = 0;j < align;j++) \
|
||||
{ \
|
||||
for(k = 0;k < numchans;k++) \
|
||||
*(dst++) = Conv_##T##_ALshort(tmp[j*numchans + k]); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
DECL_TEMPLATE(ALbyte)
|
||||
DECL_TEMPLATE(ALubyte)
|
||||
static void Convert_ALshort_ALima4(ALshort *dst, const ALima4 *src, ALuint numchans,
|
||||
ALuint len, ALuint align)
|
||||
void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len,
|
||||
ALsizei align)
|
||||
{
|
||||
ALsizei byte_align = ((align-1)/2 + 4) * numchans;
|
||||
ALuint i;
|
||||
ALsizei i;
|
||||
|
||||
assert(align > 0 && (len%align) == 0);
|
||||
for(i = 0;i < len;i += align)
|
||||
@@ -707,99 +259,12 @@ static void Convert_ALshort_ALima4(ALshort *dst, const ALima4 *src, ALuint numch
|
||||
dst += align*numchans;
|
||||
}
|
||||
}
|
||||
DECL_TEMPLATE(ALushort)
|
||||
DECL_TEMPLATE(ALint)
|
||||
DECL_TEMPLATE(ALuint)
|
||||
DECL_TEMPLATE(ALfloat)
|
||||
DECL_TEMPLATE(ALdouble)
|
||||
DECL_TEMPLATE(ALmulaw)
|
||||
DECL_TEMPLATE(ALalaw)
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
#define DECL_TEMPLATE(T) \
|
||||
static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALuint numchans, \
|
||||
ALuint len, ALuint align) \
|
||||
{ \
|
||||
ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; \
|
||||
ALint index[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; \
|
||||
ALsizei byte_align = ((align-1)/2 + 4) * numchans; \
|
||||
DECL_VLA(ALshort, tmp, align*numchans); \
|
||||
ALuint i, j, k; \
|
||||
\
|
||||
assert(align > 0 && (len%align) == 0); \
|
||||
for(i = 0;i < len;i += align) \
|
||||
{ \
|
||||
for(j = 0;j < align;j++) \
|
||||
{ \
|
||||
for(k = 0;k < numchans;k++) \
|
||||
tmp[j*numchans + k] = Conv_ALshort_##T(*(src++)); \
|
||||
} \
|
||||
EncodeIMA4Block(dst, tmp, sample, index, numchans, align); \
|
||||
dst += byte_align; \
|
||||
} \
|
||||
}
|
||||
|
||||
DECL_TEMPLATE(ALbyte)
|
||||
DECL_TEMPLATE(ALubyte)
|
||||
static void Convert_ALima4_ALshort(ALima4 *dst, const ALshort *src,
|
||||
ALuint numchans, ALuint len, ALuint align)
|
||||
{
|
||||
ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0};
|
||||
ALint index[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0};
|
||||
ALsizei byte_align = ((align-1)/2 + 4) * numchans;
|
||||
ALuint i;
|
||||
|
||||
assert(align > 0 && (len%align) == 0);
|
||||
for(i = 0;i < len;i += align)
|
||||
{
|
||||
EncodeIMA4Block(dst, src, sample, index, numchans, align);
|
||||
src += align*numchans;
|
||||
dst += byte_align;
|
||||
}
|
||||
}
|
||||
DECL_TEMPLATE(ALushort)
|
||||
DECL_TEMPLATE(ALint)
|
||||
DECL_TEMPLATE(ALuint)
|
||||
DECL_TEMPLATE(ALfloat)
|
||||
DECL_TEMPLATE(ALdouble)
|
||||
DECL_TEMPLATE(ALmulaw)
|
||||
DECL_TEMPLATE(ALalaw)
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
|
||||
#define DECL_TEMPLATE(T) \
|
||||
static void Convert_##T##_ALmsadpcm(T *dst, const ALmsadpcm *src, \
|
||||
ALuint numchans, ALuint len, \
|
||||
ALuint align) \
|
||||
{ \
|
||||
ALsizei byte_align = ((align-2)/2 + 7) * numchans; \
|
||||
DECL_VLA(ALshort, tmp, align*numchans); \
|
||||
ALuint i, j, k; \
|
||||
\
|
||||
assert(align > 1 && (len%align) == 0); \
|
||||
for(i = 0;i < len;i += align) \
|
||||
{ \
|
||||
DecodeMSADPCMBlock(tmp, src, numchans, align); \
|
||||
src += byte_align; \
|
||||
\
|
||||
for(j = 0;j < align;j++) \
|
||||
{ \
|
||||
for(k = 0;k < numchans;k++) \
|
||||
*(dst++) = Conv_##T##_ALshort(tmp[j*numchans + k]); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
DECL_TEMPLATE(ALbyte)
|
||||
DECL_TEMPLATE(ALubyte)
|
||||
static void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALmsadpcm *src,
|
||||
ALuint numchans, ALuint len,
|
||||
ALuint align)
|
||||
void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len,
|
||||
ALsizei align)
|
||||
{
|
||||
ALsizei byte_align = ((align-2)/2 + 7) * numchans;
|
||||
ALuint i;
|
||||
ALsizei i;
|
||||
|
||||
assert(align > 1 && (len%align) == 0);
|
||||
for(i = 0;i < len;i += align)
|
||||
@@ -809,196 +274,3 @@ static void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALmsadpcm *src,
|
||||
dst += align*numchans;
|
||||
}
|
||||
}
|
||||
DECL_TEMPLATE(ALushort)
|
||||
DECL_TEMPLATE(ALint)
|
||||
DECL_TEMPLATE(ALuint)
|
||||
DECL_TEMPLATE(ALfloat)
|
||||
DECL_TEMPLATE(ALdouble)
|
||||
DECL_TEMPLATE(ALmulaw)
|
||||
DECL_TEMPLATE(ALalaw)
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
#define DECL_TEMPLATE(T) \
|
||||
static void Convert_ALmsadpcm_##T(ALmsadpcm *dst, const T *src, \
|
||||
ALuint numchans, ALuint len, ALuint align) \
|
||||
{ \
|
||||
ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; \
|
||||
ALsizei byte_align = ((align-2)/2 + 7) * numchans; \
|
||||
DECL_VLA(ALshort, tmp, align*numchans); \
|
||||
ALuint i, j, k; \
|
||||
\
|
||||
assert(align > 1 && (len%align) == 0); \
|
||||
for(i = 0;i < len;i += align) \
|
||||
{ \
|
||||
for(j = 0;j < align;j++) \
|
||||
{ \
|
||||
for(k = 0;k < numchans;k++) \
|
||||
tmp[j*numchans + k] = Conv_ALshort_##T(*(src++)); \
|
||||
} \
|
||||
EncodeMSADPCMBlock(dst, tmp, sample, numchans, align); \
|
||||
dst += byte_align; \
|
||||
} \
|
||||
}
|
||||
|
||||
DECL_TEMPLATE(ALbyte)
|
||||
DECL_TEMPLATE(ALubyte)
|
||||
static void Convert_ALmsadpcm_ALshort(ALmsadpcm *dst, const ALshort *src,
|
||||
ALuint numchans, ALuint len, ALuint align)
|
||||
{
|
||||
ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0};
|
||||
ALsizei byte_align = ((align-2)/2 + 7) * numchans;
|
||||
ALuint i;
|
||||
|
||||
assert(align > 1 && (len%align) == 0);
|
||||
for(i = 0;i < len;i += align)
|
||||
{
|
||||
EncodeMSADPCMBlock(dst, src, sample, numchans, align);
|
||||
src += align*numchans;
|
||||
dst += byte_align;
|
||||
}
|
||||
}
|
||||
DECL_TEMPLATE(ALushort)
|
||||
DECL_TEMPLATE(ALint)
|
||||
DECL_TEMPLATE(ALuint)
|
||||
DECL_TEMPLATE(ALfloat)
|
||||
DECL_TEMPLATE(ALdouble)
|
||||
DECL_TEMPLATE(ALmulaw)
|
||||
DECL_TEMPLATE(ALalaw)
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
/* NOTE: We don't store compressed samples internally, so these conversions
|
||||
* should never happen. */
|
||||
static void Convert_ALima4_ALima4(ALima4* UNUSED(dst), const ALima4* UNUSED(src),
|
||||
ALuint UNUSED(numchans), ALuint UNUSED(len),
|
||||
ALuint UNUSED(align))
|
||||
{
|
||||
ERR("Unexpected IMA4-to-IMA4 conversion!\n");
|
||||
}
|
||||
|
||||
static void Convert_ALmsadpcm_ALmsadpcm(ALmsadpcm* UNUSED(dst), const ALmsadpcm* UNUSED(src),
|
||||
ALuint UNUSED(numchans), ALuint UNUSED(len),
|
||||
ALuint UNUSED(align))
|
||||
{
|
||||
ERR("Unexpected MSADPCM-to-MSADPCM conversion!\n");
|
||||
}
|
||||
|
||||
static void Convert_ALmsadpcm_ALima4(ALmsadpcm* UNUSED(dst), const ALima4* UNUSED(src),
|
||||
ALuint UNUSED(numchans), ALuint UNUSED(len),
|
||||
ALuint UNUSED(align))
|
||||
{
|
||||
ERR("Unexpected IMA4-to-MSADPCM conversion!\n");
|
||||
}
|
||||
|
||||
static void Convert_ALima4_ALmsadpcm(ALima4* UNUSED(dst), const ALmsadpcm* UNUSED(src),
|
||||
ALuint UNUSED(numchans), ALuint UNUSED(len),
|
||||
ALuint UNUSED(align))
|
||||
{
|
||||
ERR("Unexpected MSADPCM-to-IMA4 conversion!\n");
|
||||
}
|
||||
|
||||
|
||||
#define DECL_TEMPLATE(T) \
|
||||
static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \
|
||||
ALsizei numchans, ALsizei len, ALsizei align) \
|
||||
{ \
|
||||
switch(srcType) \
|
||||
{ \
|
||||
case UserFmtByte: \
|
||||
Convert_##T##_ALbyte(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtUByte: \
|
||||
Convert_##T##_ALubyte(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtShort: \
|
||||
Convert_##T##_ALshort(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtUShort: \
|
||||
Convert_##T##_ALushort(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtInt: \
|
||||
Convert_##T##_ALint(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtUInt: \
|
||||
Convert_##T##_ALuint(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtFloat: \
|
||||
Convert_##T##_ALfloat(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtDouble: \
|
||||
Convert_##T##_ALdouble(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtMulaw: \
|
||||
Convert_##T##_ALmulaw(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtAlaw: \
|
||||
Convert_##T##_ALalaw(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtIMA4: \
|
||||
Convert_##T##_ALima4(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
case UserFmtMSADPCM: \
|
||||
Convert_##T##_ALmsadpcm(dst, src, numchans, len, align); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
DECL_TEMPLATE(ALbyte)
|
||||
DECL_TEMPLATE(ALubyte)
|
||||
DECL_TEMPLATE(ALshort)
|
||||
DECL_TEMPLATE(ALushort)
|
||||
DECL_TEMPLATE(ALint)
|
||||
DECL_TEMPLATE(ALuint)
|
||||
DECL_TEMPLATE(ALfloat)
|
||||
DECL_TEMPLATE(ALdouble)
|
||||
DECL_TEMPLATE(ALmulaw)
|
||||
DECL_TEMPLATE(ALalaw)
|
||||
DECL_TEMPLATE(ALima4)
|
||||
DECL_TEMPLATE(ALmsadpcm)
|
||||
|
||||
#undef DECL_TEMPLATE
|
||||
|
||||
|
||||
void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align)
|
||||
{
|
||||
switch(dstType)
|
||||
{
|
||||
case UserFmtByte:
|
||||
Convert_ALbyte(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtUByte:
|
||||
Convert_ALubyte(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtShort:
|
||||
Convert_ALshort(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtUShort:
|
||||
Convert_ALushort(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtInt:
|
||||
Convert_ALint(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtUInt:
|
||||
Convert_ALuint(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtFloat:
|
||||
Convert_ALfloat(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtDouble:
|
||||
Convert_ALdouble(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtMulaw:
|
||||
Convert_ALmulaw(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtAlaw:
|
||||
Convert_ALalaw(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtIMA4:
|
||||
Convert_ALima4(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
case UserFmtMSADPCM:
|
||||
Convert_ALmsadpcm(dst, src, srcType, numchans, len, align);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user