aboutsummaryrefslogtreecommitdiffstats
path: root/OpenAL32
diff options
context:
space:
mode:
Diffstat (limited to 'OpenAL32')
-rw-r--r--OpenAL32/Include/alAuxEffectSlot.h148
-rw-r--r--OpenAL32/Include/alBuffer.h93
-rw-r--r--OpenAL32/Include/alEffect.h77
-rw-r--r--OpenAL32/Include/alError.h20
-rw-r--r--OpenAL32/Include/alFilter.h134
-rw-r--r--OpenAL32/Include/alListener.h52
-rw-r--r--OpenAL32/Include/alMain.h1015
-rw-r--r--OpenAL32/Include/alSource.h162
-rw-r--r--OpenAL32/Include/alThunk.h20
-rw-r--r--OpenAL32/Include/alu.h454
-rw-r--r--OpenAL32/Include/bs2b.h41
-rw-r--r--OpenAL32/Include/sample_cvt.h8
-rw-r--r--OpenAL32/alAuxEffectSlot.c620
-rw-r--r--OpenAL32/alBuffer.c1282
-rw-r--r--OpenAL32/alEffect.c301
-rw-r--r--OpenAL32/alError.c54
-rw-r--r--OpenAL32/alExtension.c23
-rw-r--r--OpenAL32/alFilter.c542
-rw-r--r--OpenAL32/alListener.c264
-rw-r--r--OpenAL32/alSource.c2529
-rw-r--r--OpenAL32/alState.c401
-rw-r--r--OpenAL32/alThunk.c103
-rw-r--r--OpenAL32/event.c127
-rw-r--r--OpenAL32/sample_cvt.c1113
24 files changed, 5109 insertions, 4474 deletions
diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h
index 0f0d3ef8..03ee97d6 100644
--- a/OpenAL32/Include/alAuxEffectSlot.h
+++ b/OpenAL32/Include/alAuxEffectSlot.h
@@ -4,6 +4,7 @@
#include "alMain.h"
#include "alEffect.h"
+#include "atomic.h"
#include "align.h"
#ifdef __cplusplus
@@ -14,24 +15,36 @@ struct ALeffectStateVtable;
struct ALeffectslot;
typedef struct ALeffectState {
+ RefCount Ref;
const struct ALeffectStateVtable *vtbl;
+
+ ALfloat (*OutBuffer)[BUFFERSIZE];
+ ALsizei OutChannels;
} ALeffectState;
+void ALeffectState_Construct(ALeffectState *state);
+void ALeffectState_Destruct(ALeffectState *state);
+
struct ALeffectStateVtable {
void (*const Destruct)(ALeffectState *state);
ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
- void (*const update)(ALeffectState *state, ALCdevice *device, const struct ALeffectslot *slot);
- void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels);
+ void (*const update)(ALeffectState *state, const ALCcontext *context, const struct ALeffectslot *slot, const union ALeffectProps *props);
+ void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei numChannels);
void (*const Delete)(void *ptr);
};
+/* Small hack to use a pointer-to-array types as a normal argument type.
+ * Shouldn't be used directly.
+ */
+typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
+
#define DEFINE_ALEFFECTSTATE_VTABLE(T) \
DECLARE_THUNK(T, ALeffectState, void, Destruct) \
DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \
-DECLARE_THUNK2(T, ALeffectState, void, update, ALCdevice*, const ALeffectslot*) \
-DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \
+DECLARE_THUNK3(T, ALeffectState, void, update, const ALCcontext*, const ALeffectslot*, const ALeffectProps*) \
+DECLARE_THUNK4(T, ALeffectState, void, process, ALsizei, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALsizei) \
static void T##_ALeffectState_Delete(void *ptr) \
{ return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \
\
@@ -46,69 +59,124 @@ static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \
}
-struct ALeffectStateFactoryVtable;
+struct EffectStateFactoryVtable;
-typedef struct ALeffectStateFactory {
- const struct ALeffectStateFactoryVtable *vtbl;
-} ALeffectStateFactory;
+typedef struct EffectStateFactory {
+ const struct EffectStateFactoryVtable *vtab;
+} EffectStateFactory;
-struct ALeffectStateFactoryVtable {
- ALeffectState *(*const create)(ALeffectStateFactory *factory);
+struct EffectStateFactoryVtable {
+ ALeffectState *(*const create)(EffectStateFactory *factory);
};
+#define EffectStateFactory_create(x) ((x)->vtab->create((x)))
-#define DEFINE_ALEFFECTSTATEFACTORY_VTABLE(T) \
-DECLARE_THUNK(T, ALeffectStateFactory, ALeffectState*, create) \
+#define DEFINE_EFFECTSTATEFACTORY_VTABLE(T) \
+DECLARE_THUNK(T, EffectStateFactory, ALeffectState*, create) \
\
-static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = { \
- T##_ALeffectStateFactory_create, \
+static const struct EffectStateFactoryVtable T##_EffectStateFactory_vtable = { \
+ T##_EffectStateFactory_create, \
}
+#define MAX_EFFECT_CHANNELS (4)
+
+
+struct ALeffectslotArray {
+ ALsizei count;
+ struct ALeffectslot *slot[];
+};
+
+
+struct ALeffectslotProps {
+ ALfloat Gain;
+ ALboolean AuxSendAuto;
+
+ ALenum Type;
+ ALeffectProps Props;
+
+ ALeffectState *State;
+
+ ATOMIC(struct ALeffectslotProps*) next;
+};
+
+
typedef struct ALeffectslot {
- ALenum EffectType;
- ALeffectProps EffectProps;
+ ALfloat Gain;
+ ALboolean AuxSendAuto;
- volatile ALfloat Gain;
- volatile ALboolean AuxSendAuto;
+ struct {
+ ALenum Type;
+ ALeffectProps Props;
- ATOMIC(ALenum) NeedsUpdate;
- ALeffectState *EffectState;
+ ALeffectState *State;
+ } Effect;
- alignas(16) ALfloat WetBuffer[1][BUFFERSIZE];
+ ATOMIC_FLAG PropsClean;
RefCount ref;
+ ATOMIC(struct ALeffectslotProps*) Update;
+
+ struct {
+ ALfloat Gain;
+ ALboolean AuxSendAuto;
+
+ ALenum EffectType;
+ ALeffectProps EffectProps;
+ ALeffectState *EffectState;
+
+ ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */
+ ALfloat DecayTime;
+ ALfloat DecayLFRatio;
+ ALfloat DecayHFRatio;
+ ALboolean DecayHFLimit;
+ ALfloat AirAbsorptionGainHF;
+ } Params;
+
/* Self ID */
ALuint id;
-} ALeffectslot;
-inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
-{ return (struct ALeffectslot*)LookupUIntMapKey(&context->EffectSlotMap, id); }
-inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id)
-{ return (struct ALeffectslot*)RemoveUIntMapKey(&context->EffectSlotMap, id); }
+ ALsizei NumChannels;
+ BFChannelConfig ChanMap[MAX_EFFECT_CHANNELS];
+ /* Wet buffer configuration is ACN channel order with N3D scaling:
+ * * Channel 0 is the unattenuated mono signal.
+ * * Channel 1 is OpenAL -X * 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 source pan for first-order device
+ * output (FOAOut).
+ */
+ alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE];
+} ALeffectslot;
ALenum InitEffectSlot(ALeffectslot *slot);
+void DeinitEffectSlot(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 *ALautowahStateFactory_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 *AutowahStateFactory_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 *FshifterStateFactory_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
}
diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h
index dd046da8..fbe3e6e5 100644
--- a/OpenAL32/Include/alBuffer.h
+++ b/OpenAL32/Include/alBuffer.h
@@ -1,7 +1,13 @@
#ifndef _AL_BUFFER_H_
#define _AL_BUFFER_H_
-#include "alMain.h"
+#include "AL/alc.h"
+#include "AL/al.h"
+#include "AL/alext.h"
+
+#include "inprogext.h"
+#include "atomic.h"
+#include "rwlock.h"
#ifdef __cplusplus
extern "C" {
@@ -9,36 +15,30 @@ extern "C" {
/* User formats */
enum UserFmtType {
- UserFmtByte = AL_BYTE_SOFT,
- UserFmtUByte = AL_UNSIGNED_BYTE_SOFT,
- UserFmtShort = AL_SHORT_SOFT,
- UserFmtUShort = AL_UNSIGNED_SHORT_SOFT,
- UserFmtInt = AL_INT_SOFT,
- UserFmtUInt = AL_UNSIGNED_INT_SOFT,
- UserFmtFloat = AL_FLOAT_SOFT,
- UserFmtDouble = AL_DOUBLE_SOFT,
- UserFmtByte3 = AL_BYTE3_SOFT,
- UserFmtUByte3 = AL_UNSIGNED_BYTE3_SOFT,
+ 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 = 0x10000000, /* WXY */
+ UserFmtMono,
+ UserFmtStereo,
+ UserFmtRear,
+ UserFmtQuad,
+ UserFmtX51, /* (WFX order) */
+ UserFmtX61, /* (WFX order) */
+ UserFmtX71, /* (WFX order) */
+ UserFmtBFormat2D, /* WXY */
UserFmtBFormat3D, /* WXYZ */
};
-ALuint BytesFromUserFmt(enum UserFmtType type) DECL_CONST;
-ALuint ChannelsFromUserFmt(enum UserFmtChannels chans) DECL_CONST;
-inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type)
+ALsizei BytesFromUserFmt(enum UserFmtType type);
+ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans);
+inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type)
{
return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type);
}
@@ -46,9 +46,12 @@ inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType
/* Storable formats */
enum FmtType {
- FmtByte = UserFmtByte,
- FmtShort = UserFmtShort,
- FmtFloat = UserFmtFloat,
+ FmtUByte = UserFmtUByte,
+ FmtShort = UserFmtShort,
+ FmtFloat = UserFmtFloat,
+ FmtDouble = UserFmtDouble,
+ FmtMulaw = UserFmtMulaw,
+ FmtAlaw = UserFmtAlaw,
};
enum FmtChannels {
FmtMono = UserFmtMono,
@@ -63,9 +66,9 @@ enum FmtChannels {
};
#define MAX_INPUT_CHANNELS (8)
-ALuint BytesFromFmt(enum FmtType type) DECL_CONST;
-ALuint ChannelsFromFmt(enum FmtChannels chans) DECL_CONST;
-inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
+ALsizei BytesFromFmt(enum FmtType type);
+ALsizei ChannelsFromFmt(enum FmtChannels chans);
+inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
{
return ChannelsFromFmt(chans) * BytesFromFmt(type);
}
@@ -74,43 +77,35 @@ inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
typedef struct ALbuffer {
ALvoid *data;
- ALsizei Frequency;
- ALenum Format;
- ALsizei SampleLen;
+ ALsizei Frequency;
+ ALbitfieldSOFT Access;
+ ALsizei SampleLen;
enum FmtChannels FmtChannels;
enum FmtType FmtType;
+ ALsizei BytesAlloc;
- enum UserFmtChannels OriginalChannels;
- enum UserFmtType OriginalType;
- ALsizei OriginalSize;
- ALsizei OriginalAlign;
+ enum UserFmtType OriginalType;
+ ALsizei OriginalSize;
+ ALsizei OriginalAlign;
- ALsizei LoopStart;
- ALsizei LoopEnd;
+ ALsizei LoopStart;
+ ALsizei LoopEnd;
ATOMIC(ALsizei) UnpackAlign;
ATOMIC(ALsizei) PackAlign;
+ ALbitfieldSOFT MappedAccess;
+ ALsizei MappedOffset;
+ ALsizei MappedSize;
+
/* Number of times buffer was attached to a source (deletion can only occur when 0) */
RefCount ref;
- RWLock lock;
-
/* Self ID */
ALuint id;
} ALbuffer;
-ALbuffer *NewBuffer(ALCcontext *context);
-void DeleteBuffer(ALCdevice *device, ALbuffer *buffer);
-
-ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc);
-
-inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
-{ return (struct ALbuffer*)LookupUIntMapKey(&device->BufferMap, id); }
-inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id)
-{ return (struct ALbuffer*)RemoveUIntMapKey(&device->BufferMap, id); }
-
ALvoid ReleaseALBuffers(ALCdevice *device);
#ifdef __cplusplus
diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h
index 91ee782f..7b849c0c 100644
--- a/OpenAL32/Include/alEffect.h
+++ b/OpenAL32/Include/alEffect.h
@@ -10,24 +10,34 @@ extern "C" {
struct ALeffect;
enum {
- EAXREVERB = 0,
- REVERB,
- AUTOWAH,
- CHORUS,
- COMPRESSOR,
- DISTORTION,
- ECHO,
- EQUALIZER,
- FLANGER,
- MODULATOR,
- DEDICATED,
+ EAXREVERB_EFFECT = 0,
+ REVERB_EFFECT,
+ AUTOWAH_EFFECT,
+ CHORUS_EFFECT,
+ COMPRESSOR_EFFECT,
+ DISTORTION_EFFECT,
+ ECHO_EFFECT,
+ EQUALIZER_EFFECT,
+ FLANGER_EFFECT,
+ FSHIFTER_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 14
+extern const struct EffectList EffectList[EFFECTLIST_SIZE];
+
struct ALeffectVtable {
void (*const setParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val);
@@ -58,8 +68,10 @@ extern const struct ALeffectVtable ALdistortion_vtable;
extern const struct ALeffectVtable ALecho_vtable;
extern const struct ALeffectVtable ALequalizer_vtable;
extern const struct ALeffectVtable ALflanger_vtable;
+extern const struct ALeffectVtable ALfshifter_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;
@@ -96,8 +108,8 @@ typedef union ALeffectProps {
struct {
ALfloat AttackTime;
ALfloat ReleaseTime;
- ALfloat PeakGain;
ALfloat Resonance;
+ ALfloat PeakGain;
} Autowah;
struct {
@@ -107,7 +119,7 @@ typedef union ALeffectProps {
ALfloat Depth;
ALfloat Feedback;
ALfloat Delay;
- } Chorus;
+ } Chorus; /* Also Flanger */
struct {
ALboolean OnOff;
@@ -145,13 +157,10 @@ typedef union ALeffectProps {
} Equalizer;
struct {
- ALint Waveform;
- ALint Phase;
- ALfloat Rate;
- ALfloat Depth;
- ALfloat Feedback;
- ALfloat Delay;
- } Flanger;
+ ALfloat Frequency;
+ ALint LeftDirection;
+ ALint RightDirection;
+ } Fshifter;
struct {
ALfloat Frequency;
@@ -160,6 +169,11 @@ typedef union ALeffectProps {
} Modulator;
struct {
+ ALint CoarseTune;
+ ALint FineTune;
+ } Pshifter;
+
+ struct {
ALfloat Gain;
} Dedicated;
} ALeffectProps;
@@ -170,24 +184,27 @@ typedef struct ALeffect {
ALeffectProps Props;
- const struct ALeffectVtable *vtbl;
+ const struct ALeffectVtable *vtab;
/* Self ID */
ALuint id;
} ALeffect;
-
-inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id)
-{ return (struct ALeffect*)LookupUIntMapKey(&device->EffectMap, id); }
-inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id)
-{ return (struct ALeffect*)RemoveUIntMapKey(&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
}
diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h
index ab91d27b..858f81de 100644
--- a/OpenAL32/Include/alError.h
+++ b/OpenAL32/Include/alError.h
@@ -2,6 +2,7 @@
#define _AL_ERROR_H_
#include "alMain.h"
+#include "logging.h"
#ifdef __cplusplus
extern "C" {
@@ -9,21 +10,16 @@ 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); \
+#define SETERR_GOTO(ctx, err, lbl, ...) do { \
+ alSetError((ctx), (err), __VA_ARGS__); \
+ goto lbl; \
} while(0)
-#define SET_ERROR_AND_GOTO(ctx, err, lbl) do { \
- alSetError((ctx), (err)); \
- goto lbl; \
+#define SETERR_RETURN(ctx, err, retval, ...) do { \
+ alSetError((ctx), (err), __VA_ARGS__); \
+ return retval; \
} while(0)
#ifdef __cplusplus
diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h
index 3c65fd9f..2634d5e8 100644
--- a/OpenAL32/Include/alFilter.h
+++ b/OpenAL32/Include/alFilter.h
@@ -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,86 +12,28 @@ 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).
- */
-
-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,
-
- /** 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;
-
-typedef struct ALfilterState {
- ALfloat x[2]; /* History of two last input samples */
- ALfloat y[2]; /* History of two last output samples */
- ALfloat a[3]; /* Transfer function coefficients "a" */
- ALfloat b[3]; /* Transfer function coefficients "b" */
-
- void (*process)(struct ALfilterState *self, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples);
-} ALfilterState;
-#define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__))
-
-/* 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);
-}
-/* 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));
-}
-
-void ALfilterState_clear(ALfilterState *filter);
-void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ);
+struct ALfilter;
-inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample)
-{
- ALfloat outsmp;
+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);
- outsmp = filter->b[0] * sample +
- filter->b[1] * filter->x[0] +
- filter->b[2] * filter->x[1] -
- filter->a[1] * filter->y[0] -
- filter->a[2] * filter->y[1];
- filter->x[1] = filter->x[0];
- filter->x[0] = sample;
- filter->y[1] = filter->y[0];
- filter->y[0] = outsmp;
+ 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;
- return outsmp;
+#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, \
}
-void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples);
-
-void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples);
-
-
typedef struct ALfilter {
// Filter type (AL_FILTER_NULL, ...)
ALenum type;
@@ -103,36 +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(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 struct ALfilter *LookupFilter(ALCdevice *device, ALuint id)
-{ return (struct ALfilter*)LookupUIntMapKey(&device->FilterMap, id); }
-inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id)
-{ return (struct ALfilter*)RemoveUIntMapKey(&device->FilterMap, id); }
-
-ALvoid ReleaseALFilters(ALCdevice *device);
+#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))
+
+void ReleaseALFilters(ALCdevice *device);
#ifdef __cplusplus
}
diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h
index c9bd9be0..0d80a8d7 100644
--- a/OpenAL32/Include/alListener.h
+++ b/OpenAL32/Include/alListener.h
@@ -8,20 +8,58 @@
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;
+
+ ATOMIC(struct ALlistenerProps*) next;
+};
+
typedef struct ALlistener {
- aluVector Position;
- aluVector Velocity;
- volatile ALfloat Forward[3];
- volatile ALfloat Up[3];
- volatile ALfloat Gain;
- volatile ALfloat MetersPerUnit;
+ alignas(16) ALfloat Position[3];
+ ALfloat Velocity[3];
+ ALfloat Forward[3];
+ ALfloat Up[3];
+ ALfloat Gain;
+
+ ATOMIC_FLAG PropsClean;
+
+ /* Pointer to the most recent property values that are awaiting an update.
+ */
+ ATOMIC(struct ALlistenerProps*) Update;
struct {
- aluMatrixd Matrix;
+ aluMatrixf Matrix;
aluVector Velocity;
+
+ ALfloat Gain;
+ ALfloat MetersPerUnit;
+
+ ALfloat DopplerFactor;
+ ALfloat SpeedOfSound; /* in units per sec! */
+ ALfloat ReverbSpeedOfSound; /* in meters per sec! */
+
+ ALboolean SourceDistanceModel;
+ enum DistanceModel DistanceModel;
} Params;
} ALlistener;
+void UpdateListenerProps(ALCcontext *context);
+
#ifdef __cplusplus
}
#endif
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index 8f1fd956..0fd77491 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -3,6 +3,7 @@
#include <string.h>
#include <stdio.h>
+#include <stddef.h>
#include <stdarg.h>
#include <assert.h>
#include <math.h>
@@ -11,15 +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 "vector.h"
+#include "alstring.h"
+#include "almalloc.h"
+#include "threads.h"
+
#if defined(_WIN64)
#define SZFMT "%I64u"
@@ -29,38 +40,38 @@
#define SZFMT "%zu"
#endif
-
-#include "static_assert.h"
-#include "align.h"
-#include "atomic.h"
-#include "uintmap.h"
-#include "vector.h"
-#include "alstring.h"
-
-#include "hrtf.h"
-
-#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
-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
+#ifdef __has_builtin
+#define HAS_BUILTIN __has_builtin
+#else
+#define HAS_BUILTIN(x) (0)
#endif
+#ifdef __GNUC__
+/* LIKELY optimizes the case where the condition is true. The condition is not
+ * required to be true, but it can result in more optimal code for the true
+ * path at the expense of a less optimal false path.
+ */
+#define LIKELY(x) __builtin_expect(!!(x), !0)
+/* The opposite of LIKELY, optimizing the case where the condition is false. */
+#define UNLIKELY(x) __builtin_expect(!!(x), 0)
+/* Unlike LIKELY, ASSUME requires the condition to be true or else it invokes
+ * undefined behavior. It's essentially an assert without actually checking the
+ * condition at run-time, allowing for stronger optimizations than LIKELY.
+ */
+#if HAS_BUILTIN(__builtin_assume)
+#define ASSUME __builtin_assume
+#else
+#define ASSUME(x) do { if(!(x)) __builtin_unreachable(); } while(0)
+#endif
-typedef ALint64SOFT ALint64;
-typedef ALuint64SOFT ALuint64;
+#else
-#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))
+#define LIKELY(x) (!!(x))
+#define UNLIKELY(x) (!!(x))
+#ifdef _MSC_VER
+#define ASSUME __assume
+#else
+#define ASSUME(x) ((void)0)
#endif
#endif
@@ -80,141 +91,127 @@ typedef ALuint64SOFT ALuint64;
#endif
#endif
-#ifdef __GNUC__
-#define DECL_CONST __attribute__((const))
-#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z))))
-#else
-#define DECL_CONST
-#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
-#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))
+#ifdef __cplusplus
+extern "C" {
#endif
-#ifndef PATH_MAX
-#ifdef MAX_PATH
-#define PATH_MAX MAX_PATH
-#else
-#define PATH_MAX 4096
+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
#endif
+#ifndef I64
+#if defined(_MSC_VER)
+#define I64(x) ((ALint64)(x##i64))
+#elif SIZEOF_LONG == 8
+#define I64(x) ((ALint64)(x##l))
+#elif SIZEOF_LONG_LONG == 8
+#define I64(x) ((ALint64)(x##ll))
+#endif
+#endif
-static const union {
- ALuint u;
- ALubyte b[sizeof(ALuint)];
-} EndianTest = { 1 };
-#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1)
-
-#define COUNTOF(x) (sizeof((x))/sizeof((x)[0]))
-
-
-#define DERIVE_FROM_TYPE(t) t t##_parent
-#define STATIC_CAST(to, obj) (&(obj)->to##_parent)
+/* Define a CTZ64 macro (count trailing zeros, for 64-bit integers). The result
+ * is *UNDEFINED* if the value is 0.
+ */
#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)); \
-})
+
+#if SIZEOF_LONG == 8
+#define CTZ64 __builtin_ctzl
#else
-#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent)))
+#define CTZ64 __builtin_ctzll
#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)); }
+#elif defined(HAVE_BITSCANFORWARD64_INTRINSIC)
-#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); }
+inline int msvc64_ctz64(ALuint64 v)
+{
+ unsigned long idx = 64;
+ _BitScanForward64(&idx, v);
+ return (int)idx;
+}
+#define CTZ64 msvc64_ctz64
-/* Helper to extract an argument list for VCALL. Not used directly. */
-#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
+#elif defined(HAVE_BITSCANFORWARD_INTRINSIC)
-/* 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
+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 msvc_ctz64
-#define DELETE_OBJ(obj) do { \
- if((obj) != NULL) \
- { \
- V0((obj),Destruct)(); \
- V0((obj),Delete)(); \
- } \
-} while(0)
+#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);
+}
-#define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \
- } \
-} while(0)
+inline int fallback_ctz64(ALuint64 value)
+{
+ return fallback_popcnt64(~value & (value - 1));
+}
+#define CTZ64 fallback_ctz64
+#endif
-#define NEW_OBJ(_res, T) do { \
- _res = T##_New(sizeof(T)); \
- if(_res) \
- { \
- memset(_res, 0, sizeof(T)); \
- T##_Construct(_res, EXTRACT_NEW_ARGS
+#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
+#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#else
+static const union {
+ ALuint u;
+ ALubyte b[sizeof(ALuint)];
+} EndianTest = { 1 };
+#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1)
+#endif
+#define COUNTOF(x) (sizeof(x) / sizeof(0[x]))
-#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)
@@ -236,26 +233,138 @@ inline ALuint NextPowerOf2(ALuint value)
return value+1;
}
-/* Fast float-to-int conversion. Assumes the FPU is already in round-to-zero
- * mode. */
+/** Round up a value to the next multiple. */
+inline size_t RoundUp(size_t value, size_t r)
+{
+ value += r-1;
+ return value - (value%r);
+}
+
+/* Fast float-to-int conversion. No particular rounding mode is assumed; the
+ * IEEE-754 default is round-to-nearest with ties-to-even, though an app could
+ * change it on its own threads. On some systems, a truncating conversion may
+ * always be the fastest method.
+ */
inline ALint fastf2i(ALfloat f)
{
-#ifdef HAVE_LRINTF
- return lrintf(f);
-#elif defined(_MSC_VER) && defined(_M_IX86)
+#if defined(HAVE_INTRIN_H) && ((defined(_M_IX86_FP) && (_M_IX86_FP > 0)) || defined(_M_X64))
+ return _mm_cvt_ss2si(_mm_set1_ps(f));
+
+#elif defined(_MSC_VER) && defined(_M_IX86_FP)
+
ALint i;
__asm fld f
__asm fistp i
return i;
+
+#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
+
+ ALint i;
+#ifdef __SSE_MATH__
+ __asm__("cvtss2si %1, %0" : "=r"(i) : "x"(f));
#else
+ __asm__ __volatile__("fistpl %0" : "=m"(i) : "t"(f) : "st");
+#endif
+ return i;
+
+ /* On GCC when compiling with -fno-math-errno, lrintf can be inlined to
+ * some simple instructions. Clang does not inline it, always generating a
+ * libc call, while MSVC's implementation is horribly slow, so always fall
+ * back to a normal integer conversion for them.
+ */
+#elif defined(HAVE_LRINTF) && !defined(_MSC_VER) && !defined(__clang__)
+
+ return lrintf(f);
+
+#else
+
return (ALint)f;
#endif
}
-/* Fast float-to-uint conversion. Assumes the FPU is already in round-to-zero
- * mode. */
-inline ALuint fastf2u(ALfloat f)
-{ return fastf2i(f); }
+/* Converts float-to-int using standard behavior (truncation). */
+inline int float2int(float f)
+{
+#if ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \
+ !defined(__SSE_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 0)
+ ALint sign, shift, mant;
+ union {
+ ALfloat f;
+ ALint i;
+ } conv;
+
+ conv.f = f;
+ sign = (conv.i>>31) | 1;
+ shift = ((conv.i>>23)&0xff) - (127+23);
+
+ /* Over/underflow */
+ if(UNLIKELY(shift >= 31 || shift < -23))
+ return 0;
+
+ mant = (conv.i&0x7fffff) | 0x800000;
+ if(LIKELY(shift < 0))
+ return (mant >> -shift) * sign;
+ return (mant << shift) * sign;
+
+#else
+
+ return (ALint)f;
+#endif
+}
+
+/* Rounds a float to the nearest integral value, according to the current
+ * rounding mode. This is essentially an inlined version of rintf, although
+ * makes fewer promises (e.g. -0 or -0.25 rounded to 0 may result in +0).
+ */
+inline float fast_roundf(float f)
+{
+#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \
+ !defined(__SSE_MATH__)
+
+ float out;
+ __asm__ __volatile__("frndint" : "=t"(out) : "0"(f));
+ return out;
+
+#else
+
+ /* Integral limit, where sub-integral precision is not available for
+ * floats.
+ */
+ static const float ilim[2] = {
+ 8388608.0f /* 0x1.0p+23 */,
+ -8388608.0f /* -0x1.0p+23 */
+ };
+ ALuint sign, expo;
+ union {
+ ALfloat f;
+ ALuint i;
+ } conv;
+
+ conv.f = f;
+ sign = (conv.i>>31)&0x01;
+ expo = (conv.i>>23)&0xff;
+
+ if(UNLIKELY(expo >= 150/*+23*/))
+ {
+ /* An exponent (base-2) of 23 or higher is incapable of sub-integral
+ * precision, so it's already an integral value. We don't need to worry
+ * about infinity or NaN here.
+ */
+ return f;
+ }
+ /* Adding the integral limit to the value (with a matching sign) forces a
+ * result that has no sub-integral precision, and is consequently forced to
+ * round to an integral value. Removing the integral limit then restores
+ * the initial value rounded to the integral. The compiler should not
+ * optimize this out because of non-associative rules on floating-point
+ * math (as long as you don't use -fassociative-math,
+ * -funsafe-math-optimizations, -ffast-math, or -Ofast, in which case this
+ * may break).
+ */
+ f += ilim[sign];
+ return f - ilim[sign];
+#endif
+}
enum DevProbe {
@@ -263,36 +372,6 @@ enum DevProbe {
CAPTURE_DEVICE_PROBE
};
-typedef struct {
- ALCenum (*OpenPlayback)(ALCdevice*, const ALCchar*);
- void (*ClosePlayback)(ALCdevice*);
- ALCboolean (*ResetPlayback)(ALCdevice*);
- ALCboolean (*StartPlayback)(ALCdevice*);
- void (*StopPlayback)(ALCdevice*);
-
- ALCenum (*OpenCapture)(ALCdevice*, const ALCchar*);
- void (*CloseCapture)(ALCdevice*);
- void (*StartCapture)(ALCdevice*);
- void (*StopCapture)(ALCdevice*);
- ALCenum (*CaptureSamples)(ALCdevice*, void*, ALCuint);
- ALCuint (*AvailableSamples)(ALCdevice*);
-} BackendFuncs;
-
-ALCboolean alc_sndio_init(BackendFuncs *func_list);
-void alc_sndio_deinit(void);
-void alc_sndio_probe(enum DevProbe type);
-ALCboolean alc_ca_init(BackendFuncs *func_list);
-void alc_ca_deinit(void);
-void alc_ca_probe(enum DevProbe type);
-ALCboolean alc_opensl_init(BackendFuncs *func_list);
-void alc_opensl_deinit(void);
-void alc_opensl_probe(enum DevProbe type);
-ALCboolean alc_qsa_init(BackendFuncs *func_list);
-void alc_qsa_deinit(void);
-void alc_qsa_probe(enum DevProbe type);
-
-struct ALCbackend;
-
enum DistanceModel {
InverseDistanceClamped = AL_INVERSE_DISTANCE_CLAMPED,
@@ -317,10 +396,31 @@ enum Channel {
SideLeft,
SideRight,
- BFormatW,
- BFormatX,
- BFormatY,
- BFormatZ,
+ UpperFrontLeft,
+ UpperFrontRight,
+ UpperBackLeft,
+ UpperBackRight,
+ LowerFrontLeft,
+ LowerFrontRight,
+ LowerBackLeft,
+ LowerBackRight,
+
+ Aux0,
+ Aux1,
+ Aux2,
+ Aux3,
+ Aux4,
+ Aux5,
+ Aux6,
+ Aux7,
+ Aux8,
+ Aux9,
+ Aux10,
+ Aux11,
+ Aux12,
+ Aux13,
+ Aux14,
+ Aux15,
InvalidChannel
};
@@ -345,30 +445,36 @@ enum DevFmtChannels {
DevFmtX51 = ALC_5POINT1_SOFT,
DevFmtX61 = ALC_6POINT1_SOFT,
DevFmtX71 = ALC_7POINT1_SOFT,
+ DevFmtAmbi3D = ALC_BFORMAT3D_SOFT,
/* Similar to 5.1, except using rear channels instead of sides */
DevFmtX51Rear = 0x80000000,
- DevFmtBFormat3D,
-
DevFmtChannelsDefault = DevFmtStereo
};
-#define MAX_OUTPUT_CHANNELS (8)
+#define MAX_OUTPUT_CHANNELS (16)
-ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST;
-ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST;
-inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type)
+ALsizei BytesFromDevFmt(enum DevFmtType type);
+ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans, ALsizei ambiorder);
+inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type, ALsizei ambiorder)
{
- return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type);
+ return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type);
}
+enum AmbiLayout {
+ AmbiLayout_FuMa = ALC_FUMA_SOFT, /* FuMa channel order */
+ AmbiLayout_ACN = ALC_ACN_SOFT, /* ACN channel order */
-extern const struct EffectList {
- const char *name;
- int type;
- const char *ename;
- ALenum val;
-} EffectList[];
+ AmbiLayout_Default = AmbiLayout_ACN
+};
+
+enum AmbiNorm {
+ AmbiNorm_FuMa = ALC_FUMA_SOFT, /* FuMa normalization */
+ AmbiNorm_SN3D = ALC_SN3D_SOFT, /* SN3D normalization */
+ AmbiNorm_N3D = ALC_N3D_SOFT, /* N3D normalization */
+
+ AmbiNorm_Default = AmbiNorm_SN3D
+};
enum DeviceType {
@@ -378,112 +484,232 @@ enum DeviceType {
};
-enum HrtfMode {
- DisabledHrtf,
- BasicHrtf,
- FullHrtf
+enum RenderMode {
+ NormalRender,
+ StereoPair,
+ HrtfRender
};
/* The maximum number of Ambisonics coefficients. For a given order (o), the
* size needed will be (o+1)**2, thus zero-order has 1, first-order has 4,
- * second-order has 9, and third-order has 16. */
-#define MAX_AMBI_COEFFS 16
+ * second-order has 9, third-order has 16, and fourth-order has 25.
+ */
+#define MAX_AMBI_ORDER 3
+#define MAX_AMBI_COEFFS ((MAX_AMBI_ORDER+1) * (MAX_AMBI_ORDER+1))
+
+/* A bitmask of ambisonic channels with height information. If none of these
+ * channels are used/needed, there's no height (e.g. with most surround sound
+ * speaker setups). This only specifies up to 4th order, which is the highest
+ * order a 32-bit mask value can specify (a 64-bit mask could handle up to 7th
+ * order). This is ACN ordering, with bit 0 being ACN 0, etc.
+ */
+#define AMBI_PERIPHONIC_MASK (0xfe7ce4)
+
+/* The maximum number of Ambisonic coefficients for 2D (non-periphonic)
+ * representation. This is 2 per each order above zero-order, plus 1 for zero-
+ * order. Or simply, o*2 + 1.
+ */
+#define MAX_AMBI2D_COEFFS (MAX_AMBI_ORDER*2 + 1)
+
typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS];
+typedef struct BFChannelConfig {
+ ALfloat Scale;
+ ALsizei Index;
+} BFChannelConfig;
+
+typedef union AmbiConfig {
+ /* Ambisonic coefficients for mixing to the dry buffer. */
+ ChannelConfig Coeffs[MAX_OUTPUT_CHANNELS];
+ /* Coefficient channel mapping for mixing to the dry buffer. */
+ BFChannelConfig Map[MAX_OUTPUT_CHANNELS];
+} AmbiConfig;
+
+
+typedef struct BufferSubList {
+ ALuint64 FreeMask;
+ struct ALbuffer *Buffers; /* 64 */
+} BufferSubList;
+TYPEDEF_VECTOR(BufferSubList, vector_BufferSubList)
+
+typedef struct EffectSubList {
+ ALuint64 FreeMask;
+ struct ALeffect *Effects; /* 64 */
+} EffectSubList;
+TYPEDEF_VECTOR(EffectSubList, vector_EffectSubList)
+
+typedef struct FilterSubList {
+ ALuint64 FreeMask;
+ struct ALfilter *Filters; /* 64 */
+} FilterSubList;
+TYPEDEF_VECTOR(FilterSubList, vector_FilterSubList)
+
+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)
-#define HRTF_HISTORY_BITS (6)
-#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
-#define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1)
+typedef struct EnumeratedHrtf {
+ al_string name;
-typedef struct HrtfState {
- alignas(16) ALfloat History[HRTF_HISTORY_LENGTH];
- alignas(16) ALfloat Values[HRIR_LENGTH][2];
-} HrtfState;
+ struct HrtfEntry *hrtf;
+} EnumeratedHrtf;
+TYPEDEF_VECTOR(EnumeratedHrtf, vector_EnumeratedHrtf)
-typedef struct HrtfParams {
- alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
- alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2];
- ALuint Delay[2];
- ALint DelayStep[2];
-} HrtfParams;
+/* Maximum delay in samples for speaker distance compensation. */
+#define MAX_DELAY_LENGTH 1024
+
+typedef struct DistanceComp {
+ ALfloat Gain;
+ ALsizei Length; /* Valid range is [0...MAX_DELAY_LENGTH). */
+ ALfloat *Buffer;
+} DistanceComp;
/* Size for temporary storage of buffer data, in ALfloats. Larger values need
* more memory, while smaller values may need more iterations. The value needs
* to be a sensible size, however, as it constrains the max stepping value used
* for mixing, as well as the maximum number of samples per mixing iteration.
*/
-#define BUFFERSIZE (2048u)
+#define BUFFERSIZE 2048
-struct ALCdevice_struct
-{
+typedef struct MixParams {
+ 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;
+} MixParams;
+
+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;
- ALuint UpdateSize;
- ALuint NumUpdates;
+ ALuint Frequency;
+ ALuint UpdateSize;
+ ALuint NumUpdates;
enum DevFmtChannels FmtChans;
enum DevFmtType FmtType;
- ALboolean IsHeadphones;
+ ALboolean IsHeadphones;
+ ALsizei AmbiOrder;
+ /* For DevFmtAmbi* output only, specifies the channel order and
+ * normalization.
+ */
+ enum AmbiLayout AmbiLayout;
+ enum AmbiNorm AmbiScale;
+
+ ALCenum LimiterState;
al_string DeviceName;
ATOMIC(ALCenum) LastError;
// Maximum number of sources that can be created
- ALuint MaxNoOfSources;
+ ALuint SourcesMax;
// Maximum number of slots that can be created
- ALuint AuxiliaryEffectSlotMax;
+ ALuint AuxiliaryEffectSlotMax;
- ALCuint NumMonoSources;
- ALCuint NumStereoSources;
- ALuint NumAuxSends;
+ ALCuint NumMonoSources;
+ ALCuint NumStereoSources;
+ 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;
-
- /* HRTF filter tables */
- vector_HrtfEntry Hrtf_List;
- al_string Hrtf_Name;
- const struct Hrtf *Hrtf;
- ALCenum Hrtf_Status;
- enum HrtfMode Hrtf_Mode;
- HrtfState Hrtf_State[MAX_OUTPUT_CHANNELS];
- HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS];
- ALuint Hrtf_Offset;
-
- // Stereo-to-binaural filter
+ vector_FilterSubList FilterList;
+ almtx_t FilterLock;
+
+ POSTPROCESS PostProcess;
+
+ /* HRTF state and info */
+ struct DirectHrtfState *Hrtf;
+ al_string HrtfName;
+ struct Hrtf *HrtfHandle;
+ vector_EnumeratedHrtf HrtfList;
+ ALCenum HrtfStatus;
+
+ /* UHJ encoder state */
+ struct Uhj2Encoder *Uhj_Encoder;
+
+ /* High quality Ambisonic decoder */
+ struct BFormatDec *AmbiDecoder;
+
+ /* Stereo-to-binaural filter */
struct bs2b *Bs2b;
+ /* First-order ambisonic upsampler for higher-order output */
+ struct AmbiUpsampler *AmbiUp;
+
+ /* Rendering mode. */
+ enum RenderMode Render_Mode;
+
// Device flags
ALuint Flags;
- enum Channel ChannelName[MAX_OUTPUT_CHANNELS];
- ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS];
- ALfloat AmbiScale; /* Scale for first-order XYZ inputs using AmbCoeffs. */
- ALuint NumChannels;
-
ALuint64 ClockBase;
ALuint SamplesDone;
+ ALuint FixedLatency;
+
+ /* Temp storage used for mixer processing. */
+ alignas(16) ALfloat TempBuffer[4][BUFFERSIZE];
- /* Temp storage used for each source when mixing. */
- alignas(16) ALfloat SourceData[BUFFERSIZE];
- alignas(16) ALfloat ResampledData[BUFFERSIZE];
- alignas(16) ALfloat FilteredData[BUFFERSIZE];
+ /* The "dry" path corresponds to the main output. */
+ MixParams Dry;
+ ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1];
+
+ /* First-order ambisonics output, to be upsampled to the dry buffer if different. */
+ MixParams FOAOut;
+
+ /* "Real" output, which will be written to the device buffer. May alias the
+ * dry buffer.
+ */
+ RealMixParams RealOut;
- /* Dry path buffer mix. */
- alignas(16) ALfloat (*DryBuffer)[BUFFERSIZE];
+ struct FrontStablizer *Stablizer;
+
+ struct Compressor *Limiter;
+
+ /* The average speaker distance as determined by the ambdec configuration
+ * (or alternatively, by the NFC-HOA reference delay). Only used for NFC.
+ */
+ ALfloat AvgSpeakerDist;
+
+ /* Delay buffers used to compensate for speaker distances. */
+ DistanceComp ChannelDelay[MAX_OUTPUT_CHANNELS];
+
+ /* Dithering control. */
+ ALfloat DitherDepth;
+ ALuint DitherSeed;
/* Running count of the mixer invocations, in 31.1 fixed point. This
* actually increments *twice* when mixing, first at the start and then at
@@ -492,34 +718,27 @@ struct ALCdevice_struct
*/
RefCount MixCount;
- /* Default effect slot */
- struct ALeffectslot *DefaultSlot;
-
// Contexts created on this device
ATOMIC(ALCcontext*) ContextList;
+ almtx_t BackendLock;
struct ALCbackend *Backend;
- void *ExtraData; // For the backend's use
-
- ALCdevice *volatile next;
-
- /* Memory space used by the default slot (Playback devices only) */
- alignas(16) ALCbyte _slot_mem[];
+ ATOMIC(ALCdevice*) next;
};
// Frequency was requested by the app or config file
-#define DEVICE_FREQUENCY_REQUEST (1<<1)
+#define DEVICE_FREQUENCY_REQUEST (1u<<1)
// Channel configuration was requested by the config file
-#define DEVICE_CHANNELS_REQUEST (1<<2)
+#define DEVICE_CHANNELS_REQUEST (1u<<2)
// Sample type was requested by the config file
-#define DEVICE_SAMPLE_TYPE_REQUEST (1<<3)
+#define DEVICE_SAMPLE_TYPE_REQUEST (1u<<3)
// Specifies if the DSP is paused at user request
-#define DEVICE_PAUSED (1<<30)
+#define DEVICE_PAUSED (1u<<30)
// Specifies if the device is currently running
-#define DEVICE_RUNNING (1<<31)
+#define DEVICE_RUNNING (1u<<31)
/* Nanosecond resolution for the device clock time. */
@@ -533,207 +752,167 @@ struct ALCdevice_struct
#define RECORD_THREAD_NAME "alsoft-record"
-struct ALCcontext_struct
-{
+enum {
+ /* End event thread processing. */
+ EventType_KillThread = 0,
+
+ /* User event types. */
+ EventType_SourceStateChange = 1<<0,
+ EventType_BufferCompleted = 1<<1,
+ EventType_Error = 1<<2,
+ EventType_Performance = 1<<3,
+ EventType_Deprecated = 1<<4,
+ EventType_Disconnected = 1<<5,
+
+ /* Internal events. */
+ EventType_ReleaseEffectState = 65536,
+};
+
+typedef struct AsyncEvent {
+ unsigned int EnumType;
+ union {
+ char dummy;
+ struct {
+ ALenum type;
+ ALuint id;
+ ALuint param;
+ ALchar msg[1008];
+ } user;
+ struct ALeffectState *EffectState;
+ } u;
+} AsyncEvent;
+#define ASYNC_EVENT(t) { t, { 0 } }
+
+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;
- ATOMIC(ALenum) UpdateSources;
+ enum DistanceModel DistanceModel;
+ ALboolean SourceDistanceModel;
- volatile enum DistanceModel DistanceModel;
- volatile ALboolean SourceDistanceModel;
+ ALfloat DopplerFactor;
+ ALfloat DopplerVelocity;
+ ALfloat SpeedOfSound;
+ ALfloat MetersPerUnit;
- volatile ALfloat DopplerFactor;
- volatile ALfloat DopplerVelocity;
- volatile ALfloat SpeedOfSound;
- volatile ALenum DeferUpdates;
+ ATOMIC_FLAG PropsClean;
+ ATOMIC(ALenum) DeferUpdates;
- struct ALvoice *Voices;
+ almtx_t PropLock;
+
+ /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
+ * indicates if updates are currently happening).
+ */
+ RefCount UpdateCount;
+ ATOMIC(ALenum) HoldUpdates;
+
+ 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;
- VECTOR(struct ALeffectslot*) ActiveAuxSlots;
+ ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots;
+
+ 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 */
+ /* Memory space used by the listener (and possibly default effect slot) */
alignas(16) ALCbyte _listener_mem[];
};
ALCcontext *GetContextRef(void);
-void ALCcontext_IncRef(ALCcontext *context);
void ALCcontext_DecRef(ALCcontext *context);
-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);
-inline void LockContext(ALCcontext *context)
-{ ALCdevice_Lock(context->Device); }
-
-inline void UnlockContext(ALCcontext *context)
-{ ALCdevice_Unlock(context->Device); }
-
+void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends);
-void *al_malloc(size_t alignment, size_t size);
-void *al_calloc(size_t alignment, size_t size);
-void al_free(void *ptr);
-
-
-typedef struct {
-#ifdef HAVE_FENV_H
- DERIVE_FROM_TYPE(fenv_t);
-#else
- int state;
-#endif
-#ifdef HAVE_SSE
- int sse_state;
-#endif
-} FPUCtl;
-void SetMixerFPUMode(FPUCtl *ctl);
-void RestoreFPUMode(const FPUCtl *ctl);
-
-
-typedef struct RingBuffer RingBuffer;
-RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length);
-void DestroyRingBuffer(RingBuffer *ring);
-ALsizei RingBufferSize(RingBuffer *ring);
-void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len);
-void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len);
-
-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);
void SetDefaultWFXChannelOrder(ALCdevice *device);
-const ALCchar *DevFmtTypeString(enum DevFmtType type) DECL_CONST;
-const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) DECL_CONST;
+const ALCchar *DevFmtTypeString(enum DevFmtType type);
+const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans);
-/**
- * GetChannelIdxByName
- *
- * Returns the device's channel index given a channel name (e.g. FrontCenter),
- * or -1 if it doesn't exist.
- */
-inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan)
+inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan)
{
- ALint i = 0;
+ ALint i;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
{
- if(device->ChannelName[i] == chan)
+ if(names[i] == chan)
return i;
}
return -1;
}
+/**
+ * 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 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
-
-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__); \
-} while(0)
-
-#define WARN(...) do { \
- if(LogLevel >= LogWarning) \
- AL_PRINT("(WW)", __VA_ARGS__); \
-} while(0)
-
-#define ERR(...) do { \
- if(LogLevel >= LogError) \
- AL_PRINT("(EE)", __VA_ARGS__); \
-} while(0)
+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 ALint RTPrioLevel;
+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); }
-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,
-};
-void FillCPUCaps(ALuint capfilter);
+int EventThread(void *arg);
-FILE *OpenDataFile(const char *fname, const char *subdir);
vector_al_string SearchDataFiles(const char *match, const char *subdir);
-/* Small hack to use a pointer-to-array type as a normal argument type.
- * Shouldn't be used directly. */
-typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
-
-
#ifdef __cplusplus
}
#endif
diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h
index 13596161..5f07c09d 100644
--- a/OpenAL32/Include/alSource.h
+++ b/OpenAL32/Include/alSource.h
@@ -1,11 +1,14 @@
#ifndef _AL_SOURCE_H_
#define _AL_SOURCE_H_
-#define MAX_SENDS 4
-
+#include "bool.h"
#include "alMain.h"
#include "alu.h"
#include "hrtf.h"
+#include "atomic.h"
+
+#define MAX_SENDS 16
+#define DEFAULT_SENDS 2
#ifdef __cplusplus
extern "C" {
@@ -16,96 +19,51 @@ struct ALsource;
typedef struct ALbufferlistitem {
- struct ALbuffer *buffer;
- struct ALbufferlistitem *volatile next;
- struct ALbufferlistitem *volatile prev;
+ ATOMIC(struct ALbufferlistitem*) next;
+ ALsizei max_samples;
+ ALsizei num_buffers;
+ struct ALbuffer *buffers[];
} ALbufferlistitem;
-typedef struct ALvoice {
- struct ALsource *volatile Source;
-
- /** Method to update mixing parameters. */
- ALvoid (*Update)(struct ALvoice *self, const struct ALsource *source, const ALCcontext *context);
-
- /** Current target parameters used for mixing. */
- ALint Step;
-
- ALboolean IsHrtf;
-
- ALuint Offset; /* Number of output samples mixed since starting. */
-
- alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES];
-
- BsincState SincState;
-
- DirectParams Direct;
- SendParams Send[MAX_SENDS];
-} ALvoice;
-
-
typedef struct ALsource {
/** Source properties. */
- volatile ALfloat Pitch;
- volatile ALfloat Gain;
- volatile ALfloat OuterGain;
- volatile ALfloat MinGain;
- volatile ALfloat MaxGain;
- volatile ALfloat InnerAngle;
- volatile ALfloat OuterAngle;
- volatile ALfloat RefDistance;
- volatile ALfloat MaxDistance;
- volatile ALfloat RollOffFactor;
- aluVector Position;
- aluVector Velocity;
- aluVector Direction;
- volatile ALfloat Orientation[2][3];
- volatile ALboolean HeadRelative;
- volatile ALboolean Looping;
- volatile enum DistanceModel DistanceModel;
- volatile ALboolean DirectChannels;
-
- volatile ALboolean DryGainHFAuto;
- volatile ALboolean WetGainAuto;
- volatile ALboolean WetGainHFAuto;
- volatile ALfloat OuterGainHF;
-
- volatile ALfloat AirAbsorptionFactor;
- volatile ALfloat RoomRolloffFactor;
- volatile ALfloat DopplerFactor;
-
- volatile ALfloat Radius;
-
- /**
- * Last user-specified offset, and the offset type (bytes, samples, or
- * seconds).
- */
- ALdouble Offset;
- ALenum OffsetType;
-
- /** Source type (static, streaming, or undetermined) */
- volatile ALint SourceType;
-
- /** Source state (initial, playing, paused, or stopped) */
- volatile ALenum state;
- ALenum new_state;
-
- /**
- * Source offset in samples, relative to the currently playing buffer, NOT
- * the whole queue, and the fractional (fixed-point) offset to the next
- * sample.
+ ALfloat Pitch;
+ ALfloat Gain;
+ ALfloat OuterGain;
+ ALfloat MinGain;
+ ALfloat MaxGain;
+ ALfloat InnerAngle;
+ ALfloat OuterAngle;
+ ALfloat RefDistance;
+ ALfloat MaxDistance;
+ ALfloat RolloffFactor;
+ ALfloat Position[3];
+ ALfloat Velocity[3];
+ ALfloat Direction[3];
+ ALfloat Orientation[2][3];
+ ALboolean HeadRelative;
+ ALboolean Looping;
+ enum DistanceModel DistanceModel;
+ enum Resampler Resampler;
+ ALboolean DirectChannels;
+ enum SpatializeMode Spatialize;
+
+ ALboolean DryGainHFAuto;
+ ALboolean WetGainAuto;
+ ALboolean WetGainHFAuto;
+ ALfloat OuterGainHF;
+
+ ALfloat AirAbsorptionFactor;
+ ALfloat RoomRolloffFactor;
+ ALfloat DopplerFactor;
+
+ /* NOTE: Stereo pan angles are specified in radians, counter-clockwise
+ * rather than clockwise.
*/
- ALuint position;
- ALuint position_fraction;
-
- /** Source Buffer Queue info. */
- ATOMIC(ALbufferlistitem*) queue;
- ATOMIC(ALbufferlistitem*) current_buffer;
- RWLock queue_lock;
+ ALfloat StereoPan[2];
- /** Current buffer sample info. */
- ALuint NumChannels;
- ALuint SampleSize;
+ ALfloat Radius;
/** Direct filter and auxiliary send info. */
struct {
@@ -122,22 +80,36 @@ typedef struct ALsource {
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
- } Send[MAX_SENDS];
+ } *Send;
+
+ /**
+ * Last user-specified offset, and the offset type (bytes, samples, or
+ * seconds).
+ */
+ ALdouble Offset;
+ ALenum OffsetType;
+
+ /** Source type (static, streaming, or undetermined) */
+ ALint SourceType;
+
+ /** Source state (initial, playing, paused, or stopped) */
+ ALenum state;
+
+ /** Source Buffer Queue head. */
+ ALbufferlistitem *queue;
- /** Source needs to update its mixing parameters. */
- ATOMIC(ALenum) NeedsUpdate;
+ 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 struct ALsource *LookupSource(ALCcontext *context, ALuint id)
-{ return (struct ALsource*)LookupUIntMapKey(&context->SourceMap, id); }
-inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id)
-{ return (struct ALsource*)RemoveUIntMapKey(&context->SourceMap, id); }
-
-ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state);
-ALboolean ApplyOffset(ALsource *Source);
+void UpdateAllSourceProps(ALCcontext *context);
ALvoid ReleaseALSources(ALCcontext *Context);
diff --git a/OpenAL32/Include/alThunk.h b/OpenAL32/Include/alThunk.h
deleted file mode 100644
index adc77dec..00000000
--- a/OpenAL32/Include/alThunk.h
+++ /dev/null
@@ -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
-
diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h
index a309c4ab..c572fd71 100644
--- a/OpenAL32/Include/alu.h
+++ b/OpenAL32/Include/alu.h
@@ -12,31 +12,56 @@
#include "alMain.h"
#include "alBuffer.h"
-#include "alFilter.h"
#include "hrtf.h"
#include "align.h"
#include "math_defs.h"
+#include "filters/defs.h"
+#include "filters/nfc.h"
#define MAX_PITCH (255)
-/* Maximum number of buffer samples before the current pos needed for resampling. */
-#define MAX_PRE_SAMPLES 12
-
-/* Maximum number of buffer samples after the current pos needed for resampling. */
-#define MAX_POST_SAMPLES 12
+/* Maximum number of samples to pad on either end of a buffer for resampling.
+ * Note that both the beginning and end need padding!
+ */
+#define MAX_RESAMPLE_PADDING 24
#ifdef __cplusplus
extern "C" {
#endif
+struct BSincTable;
struct ALsource;
+struct ALbufferlistitem;
struct ALvoice;
+struct ALeffectslot;
+
+#define DITHER_RNG_SEED 22222
+
+
+enum SpatializeMode {
+ SpatializeOff = AL_FALSE,
+ SpatializeOn = AL_TRUE,
+ SpatializeAuto = AL_AUTO_SOFT
+};
-/* The number of distinct scale and phase intervals within the filter table. */
+enum Resampler {
+ PointResampler,
+ LinearResampler,
+ FIR4Resampler,
+ BSinc12Resampler,
+ BSinc24Resampler,
+
+ ResamplerMax = BSinc24Resampler
+};
+extern enum Resampler ResamplerDefault;
+
+/* The number of distinct scale and phase intervals within the bsinc filter
+ * table.
+ */
#define BSINC_SCALE_BITS 4
#define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
#define BSINC_PHASE_BITS 4
@@ -48,16 +73,29 @@ struct ALvoice;
*/
typedef struct BsincState {
ALfloat sf; /* Scale interpolation factor. */
- ALuint 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];
+ ALsizei m; /* Coefficient count. */
+ ALsizei l; /* Left coefficient offset. */
+ /* Filter coefficients, followed by the scale, phase, and scale-phase
+ * delta coefficients. Starting at phase index 0, each subsequent phase
+ * index follows contiguously.
+ */
+ const ALfloat *filter;
} BsincState;
+typedef union InterpState {
+ BsincState bsinc;
+} InterpState;
+
+typedef const ALfloat* (*ResamplerFunc)(const InterpState *state,
+ const ALfloat *restrict src, ALsizei frac, ALint increment,
+ ALfloat *restrict dst, ALsizei dstlen
+);
+
+void BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table);
+
+extern const struct BSincTable bsinc12;
+extern const struct BSincTable bsinc24;
+
typedef union aluVector {
alignas(16) ALfloat v[4];
@@ -75,6 +113,7 @@ inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALf
typedef union aluMatrixf {
alignas(16) ALfloat m[4][4];
} aluMatrixf;
+extern const aluMatrixf IdentityMatrixf;
inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row,
ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3)
@@ -97,31 +136,6 @@ inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat
}
-typedef union aluMatrixd {
- alignas(16) ALdouble m[4][4];
-} aluMatrixd;
-
-inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row,
- ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3)
-{
- matrix->m[row][0] = m0;
- matrix->m[row][1] = m1;
- matrix->m[row][2] = m2;
- matrix->m[row][3] = m3;
-}
-
-inline void aluMatrixdSet(aluMatrixd *matrix, ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03,
- ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13,
- ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23,
- ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33)
-{
- aluMatrixdSetRow(matrix, 0, m00, m01, m02, m03);
- aluMatrixdSetRow(matrix, 1, m10, m11, m12, m13);
- aluMatrixdSetRow(matrix, 2, m20, m21, m22, m23);
- aluMatrixdSetRow(matrix, 3, m30, m31, m32, m33);
-}
-
-
enum ActiveFilters {
AF_None = 0,
AF_LowPass = 1,
@@ -130,74 +144,199 @@ enum ActiveFilters {
};
-typedef struct MixGains {
- ALfloat Current;
- ALfloat Step;
- ALfloat Target;
-} MixGains;
+typedef struct MixHrtfParams {
+ const ALfloat (*Coeffs)[2];
+ ALsizei Delay[2];
+ ALfloat Gain;
+ ALfloat GainStep;
+} MixHrtfParams;
typedef struct DirectParams {
- ALfloat (*OutBuffer)[BUFFERSIZE];
- ALuint OutChannels;
+ BiquadFilter LowPass;
+ BiquadFilter HighPass;
- /* If not 'moving', gain/coefficients are set directly without fading. */
- ALboolean Moving;
- /* Stepping counter for gain/coefficient fading. */
- ALuint Counter;
- /* Last direction (relative to listener) and gain of a moving source. */
- aluVector LastDir;
- ALfloat LastGain;
+ NfcFilter NFCtrlFilter;
struct {
- enum ActiveFilters ActiveType;
- ALfilterState LowPass;
- ALfilterState HighPass;
- } Filters[MAX_INPUT_CHANNELS];
+ HrtfParams Old;
+ HrtfParams Target;
+ HrtfState State;
+ } Hrtf;
struct {
- HrtfParams Params;
- HrtfState State;
- } Hrtf[MAX_INPUT_CHANNELS];
- MixGains Gains[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
+ ALfloat Current[MAX_OUTPUT_CHANNELS];
+ ALfloat Target[MAX_OUTPUT_CHANNELS];
+ } Gains;
} DirectParams;
typedef struct SendParams {
- ALfloat (*OutBuffer)[BUFFERSIZE];
-
- ALboolean Moving;
- ALuint Counter;
+ BiquadFilter LowPass;
+ BiquadFilter HighPass;
struct {
- enum ActiveFilters ActiveType;
- ALfilterState LowPass;
- ALfilterState HighPass;
- } Filters[MAX_INPUT_CHANNELS];
-
- /* Gain control, which applies to each input channel to a single (mono)
- * output buffer. */
- MixGains Gains[MAX_INPUT_CHANNELS];
+ ALfloat Current[MAX_OUTPUT_CHANNELS];
+ ALfloat Target[MAX_OUTPUT_CHANNELS];
+ } Gains;
} SendParams;
-typedef const ALfloat* (*ResamplerFunc)(const BsincState *state,
- const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen
-);
+struct ALvoiceProps {
+ ATOMIC(struct ALvoiceProps*) next;
+
+ ALfloat Pitch;
+ ALfloat Gain;
+ ALfloat OuterGain;
+ ALfloat MinGain;
+ ALfloat MaxGain;
+ ALfloat InnerAngle;
+ ALfloat OuterAngle;
+ ALfloat RefDistance;
+ ALfloat MaxDistance;
+ ALfloat RolloffFactor;
+ ALfloat Position[3];
+ ALfloat Velocity[3];
+ ALfloat Direction[3];
+ ALfloat Orientation[2][3];
+ ALboolean HeadRelative;
+ enum DistanceModel DistanceModel;
+ enum Resampler Resampler;
+ ALboolean DirectChannels;
+ enum SpatializeMode SpatializeMode;
+
+ ALboolean DryGainHFAuto;
+ ALboolean WetGainAuto;
+ ALboolean WetGainHFAuto;
+ ALfloat OuterGainHF;
+
+ ALfloat AirAbsorptionFactor;
+ ALfloat RoomRolloffFactor;
+ ALfloat DopplerFactor;
+
+ ALfloat StereoPan[2];
+
+ ALfloat Radius;
+
+ /** Direct filter and auxiliary send info. */
+ struct {
+ ALfloat Gain;
+ ALfloat GainHF;
+ ALfloat HFReference;
+ ALfloat GainLF;
+ ALfloat LFReference;
+ } Direct;
+ struct {
+ struct ALeffectslot *Slot;
+ ALfloat Gain;
+ ALfloat GainHF;
+ ALfloat HFReference;
+ ALfloat GainLF;
+ ALfloat LFReference;
+ } Send[];
+};
+
+#define VOICE_IS_STATIC (1<<0)
+#define VOICE_IS_FADING (1<<1) /* Fading sources use gain stepping for smooth transitions. */
+#define VOICE_HAS_HRTF (1<<2)
+#define VOICE_HAS_NFC (1<<3)
+
+typedef struct ALvoice {
+ struct ALvoiceProps *Props;
+
+ ATOMIC(struct ALvoiceProps*) Update;
+
+ ATOMIC(struct ALsource*) Source;
+ ATOMIC(bool) Playing;
+
+ /**
+ * Source offset in samples, relative to the currently playing buffer, NOT
+ * the whole queue, and the fractional (fixed-point) offset to the next
+ * sample.
+ */
+ ATOMIC(ALuint) position;
+ ATOMIC(ALsizei) position_fraction;
+
+ /* Current buffer queue item being played. */
+ ATOMIC(struct ALbufferlistitem*) current_buffer;
+
+ /* Buffer queue item to loop to at end of queue (will be NULL for non-
+ * looping voices).
+ */
+ ATOMIC(struct ALbufferlistitem*) loop_buffer;
+
+ /**
+ * Number of channels and bytes-per-sample for the attached source's
+ * buffer(s).
+ */
+ ALsizei NumChannels;
+ ALsizei SampleSize;
-typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans,
- ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains,
- ALuint Counter, ALuint OutPos, ALuint BufferSize);
-typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- ALuint Counter, ALuint Offset, ALuint OutPos,
- const ALuint IrSize, const HrtfParams *hrtfparams,
- HrtfState *hrtfstate, ALuint BufferSize);
+ /** Current target parameters used for mixing. */
+ ALint Step;
+ ResamplerFunc Resampler;
+
+ ALuint Flags;
+
+ ALuint Offset; /* Number of output samples mixed since starting. */
+
+ alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_RESAMPLE_PADDING];
+
+ InterpState ResampleState;
+
+ struct {
+ enum ActiveFilters FilterType;
+ DirectParams Params[MAX_INPUT_CHANNELS];
+
+ ALfloat (*Buffer)[BUFFERSIZE];
+ ALsizei Channels;
+ ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1];
+ } Direct;
+
+ struct {
+ enum ActiveFilters FilterType;
+ SendParams Params[MAX_INPUT_CHANNELS];
+
+ ALfloat (*Buffer)[BUFFERSIZE];
+ ALsizei Channels;
+ } Send[];
+} ALvoice;
+
+void DeinitVoice(ALvoice *voice);
+
+
+typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans,
+ ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains,
+ const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
+ ALsizei BufferSize);
+typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains,
+ const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans,
+ ALsizei InPos, ALsizei BufferSize);
+typedef void (*HrtfMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+ const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+ const ALsizei IrSize, MixHrtfParams *hrtfparams,
+ HrtfState *hrtfstate, ALsizei BufferSize);
+typedef void (*HrtfMixerBlendFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+ const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+ const ALsizei IrSize, const HrtfParams *oldparams,
+ MixHrtfParams *newparams, HrtfState *hrtfstate,
+ ALsizei BufferSize);
+typedef void (*HrtfDirectMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+ const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
+ const ALfloat (*restrict Coeffs)[2],
+ ALfloat (*restrict Values)[2], ALsizei BufferSize);
+
+
+#define GAIN_MIX_MAX (16.0f) /* +24dB */
#define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */
+/* Target gain for the reverb decay feedback reaching the decay time. */
+#define REVERB_DECAY_GAIN (0.001f) /* -60 dB */
+
#define FRACTIONBITS (12)
#define FRACTIONONE (1<<FRACTIONBITS)
#define FRACTIONMASK (FRACTIONONE-1)
@@ -245,83 +384,148 @@ inline ALuint64 maxu64(ALuint64 a, ALuint64 b)
inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
{ return minu64(max, maxu64(min, val)); }
-
-union ResamplerCoeffs {
- ALfloat FIR4[FRACTIONONE][4];
- ALfloat FIR8[FRACTIONONE][8];
-};
-extern alignas(16) union ResamplerCoeffs ResampleCoeffs;
-
-extern alignas(16) const ALfloat bsincTab[18840];
+inline size_t minz(size_t a, size_t b)
+{ return ((a > b) ? b : a); }
+inline size_t maxz(size_t a, size_t b)
+{ return ((a > b) ? a : b); }
+inline size_t clampz(size_t val, size_t min, size_t max)
+{ return minz(max, maxz(min, val)); }
inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
{
return val1 + (val2-val1)*mu;
}
-inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac)
-{
- const ALfloat *k = ResampleCoeffs.FIR4[frac];
- return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3;
-}
-inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac)
+inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu)
{
- const ALfloat *k = ResampleCoeffs.FIR8[frac];
- return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3 +
- k[4]*val4 + k[5]*val5 + k[6]*val6 + k[7]*val7;
+ ALfloat mu2 = mu*mu, mu3 = mu2*mu;
+ ALfloat a0 = -0.5f*mu3 + mu2 + -0.5f*mu;
+ ALfloat a1 = 1.5f*mu3 + -2.5f*mu2 + 1.0f;
+ ALfloat a2 = -1.5f*mu3 + 2.0f*mu2 + 0.5f*mu;
+ ALfloat a3 = 0.5f*mu3 + -0.5f*mu2;
+ return val1*a0 + val2*a1 + val3*a2 + val4*a3;
}
+enum HrtfRequestMode {
+ Hrtf_Default = 0,
+ Hrtf_Enable = 1,
+ Hrtf_Disable = 2,
+};
+
+void aluInit(void);
+
void aluInitMixer(void);
-ALvoid aluInitPanning(ALCdevice *Device);
+ResamplerFunc SelectResampler(enum Resampler resampler);
+
+/* aluInitRenderer
+ *
+ * Set up the appropriate panning method and mixing method given the device
+ * properties.
+ */
+void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq);
+
+void aluInitEffectPanning(struct ALeffectslot *slot);
+
+void aluSelectPostProcess(ALCdevice *device);
/**
- * ComputeDirectionalGains
+ * Calculates ambisonic encoder coefficients using the X, Y, and Z direction
+ * components, which must represent a normalized (unit length) vector, and the
+ * spread is the angular width of the sound (0...tau).
+ *
+ * NOTE: The components use ambisonic coordinates. As a result:
+ *
+ * Ambisonic Y = OpenAL -X
+ * Ambisonic Z = OpenAL Y
+ * Ambisonic X = OpenAL -Z
*
- * Sets channel gains based on a direction. The direction must be a 3-component
- * vector no longer than 1 unit.
+ * The components are ordered such that OpenAL's X, Y, and Z are the first,
+ * second, and third parameters respectively -- simply negate X and Z.
*/
-void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread,
+ ALfloat coeffs[MAX_AMBI_COEFFS]);
/**
- * ComputeAngleGains
+ * CalcDirectionCoeffs
*
- * Sets channel gains based on angle and elevation. The angle and elevation
- * parameters are in radians, going right and up respectively.
+ * Calculates ambisonic coefficients based on an OpenAL direction vector. The
+ * vector must be normalized (unit length), and the spread is the angular width
+ * of the sound (0...tau).
*/
-void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
+{
+ /* Convert from OpenAL coords to Ambisonics. */
+ CalcAmbiCoeffs(-dir[0], dir[1], -dir[2], spread, coeffs);
+}
/**
- * ComputeAmbientGains
+ * CalcAngleCoeffs
*
- * Sets channel gains for ambient, omni-directional sounds.
+ * Calculates ambisonic coefficients based on azimuth and elevation. The
+ * azimuth and elevation parameters are in radians, going right and up
+ * respectively.
*/
-void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
+{
+ ALfloat x = -sinf(azimuth) * cosf(elevation);
+ ALfloat y = sinf(elevation);
+ ALfloat z = cosf(azimuth) * cosf(elevation);
+
+ CalcAmbiCoeffs(x, y, z, spread, coeffs);
+}
/**
- * ComputeBFormatGains
+ * ScaleAzimuthFront
*
- * Sets channel gains for a given (first-order) B-Format channel. The matrix is
- * a 1x4 'slice' of the rotation matrix for a given channel used to orient the
- * coefficients.
+ * Scales the given azimuth toward the side (+/- pi/2 radians) for positions in
+ * front.
*/
-void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+inline float ScaleAzimuthFront(float azimuth, float scale)
+{
+ ALfloat sign = copysignf(1.0f, azimuth);
+ if(!(fabsf(azimuth) > F_PI_2))
+ return minf(fabsf(azimuth) * scale, F_PI_2) * sign;
+ return azimuth;
+}
+
+
+void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+
+/**
+ * ComputePanGains
+ *
+ * Computes panning gains using the given channel decoder coefficients and the
+ * pre-calculated direction or angle coefficients. For B-Format sources, the
+ * coeffs are a 'slice' of a transform matrix for the input channel, used to
+ * scale and orient the sound samples.
+ */
+inline void ComputePanGains(const MixParams *dry, const ALfloat*restrict 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);
+}
-ALvoid UpdateContextSources(ALCcontext *context);
+ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo);
-ALvoid CalcSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext);
-ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext);
+void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples);
+/* Caller must lock the device, and the mixer must not be running. */
+void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3);
-ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo);
+void UpdateContextProps(ALCcontext *context);
-ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
-/* Caller must lock the device. */
-ALvoid aluHandleDisconnect(ALCdevice *device);
+extern MixerFunc MixSamples;
+extern RowMixerFunc MixRowSamples;
extern ALfloat ConeScale;
extern ALfloat ZScale;
+extern ALboolean OverrideReverbSpeedOfSound;
#ifdef __cplusplus
}
diff --git a/OpenAL32/Include/bs2b.h b/OpenAL32/Include/bs2b.h
index 903c6bc5..e845d906 100644
--- a/OpenAL32/Include/bs2b.h
+++ b/OpenAL32/Include/bs2b.h
@@ -63,10 +63,10 @@ struct bs2b {
* [0] - first channel, [1] - second channel
*/
struct t_last_sample {
- float asis[2];
- float lo[2];
- float hi[2];
- } last_sample;
+ float asis;
+ float lo;
+ float hi;
+ } last_sample[2];
};
/* Clear buffers and set new coefficients with new crossfeed level and sample
@@ -85,38 +85,7 @@ int bs2b_get_srate(struct bs2b *bs2b);
/* Clear buffer */
void bs2b_clear(struct bs2b *bs2b);
-/* Crossfeeds one stereo sample that are pointed by sample.
- * [0] - first channel, [1] - second channel.
- * Returns crossfided sample by sample pointer.
- */
-inline void bs2b_cross_feed(struct bs2b *bs2b, float *restrict sample)
-{
-/* Single pole IIR filter.
- * O[n] = a0*I[n] + a1*I[n-1] + b1*O[n-1]
- */
-
-/* Lowpass filter */
-#define lo_filter(in, out_1) (bs2b->a0_lo*(in) + bs2b->b1_lo*(out_1))
-
-/* Highboost filter */
-#define hi_filter(in, in_1, out_1) (bs2b->a0_hi*(in) + bs2b->a1_hi*(in_1) + bs2b->b1_hi*(out_1))
-
- /* Lowpass filter */
- bs2b->last_sample.lo[0] = lo_filter(sample[0], bs2b->last_sample.lo[0]);
- bs2b->last_sample.lo[1] = lo_filter(sample[1], bs2b->last_sample.lo[1]);
-
- /* Highboost filter */
- bs2b->last_sample.hi[0] = hi_filter(sample[0], bs2b->last_sample.asis[0], bs2b->last_sample.hi[0]);
- bs2b->last_sample.hi[1] = hi_filter(sample[1], bs2b->last_sample.asis[1], bs2b->last_sample.hi[1]);
- bs2b->last_sample.asis[0] = sample[0];
- bs2b->last_sample.asis[1] = sample[1];
-
- /* Crossfeed */
- sample[0] = bs2b->last_sample.hi[0] + bs2b->last_sample.lo[1];
- sample[1] = bs2b->last_sample.hi[1] + bs2b->last_sample.lo[0];
-#undef hi_filter
-#undef lo_filter
-} /* bs2b_cross_feed */
+void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, int SamplesToDo);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/OpenAL32/Include/sample_cvt.h b/OpenAL32/Include/sample_cvt.h
index 12bb1fa6..c041760e 100644
--- a/OpenAL32/Include/sample_cvt.h
+++ b/OpenAL32/Include/sample_cvt.h
@@ -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 */
diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c
index c1314301..8141e0f6 100644
--- a/OpenAL32/alAuxEffectSlot.c
+++ b/OpenAL32/alAuxEffectSlot.c
@@ -27,83 +27,145 @@
#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 LockEffectSlotList(ALCcontext *context);
+extern inline void UnlockEffectSlotList(ALCcontext *context);
+
+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_AUTOWAH, AutowahStateFactory_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_FREQUENCY_SHIFTER, FshifterStateFactory_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)
+{
+ size_t i;
+ for(i = 0;i < COUNTOF(FactoryList);i++)
+ {
+ if(FactoryList[i].Type == type)
+ return FactoryList[i].GetFactory();
+ }
+ return NULL;
+}
-extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id);
-extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id);
+static void ALeffectState_IncRef(ALeffectState *state);
-static ALenum AddEffectSlotArray(ALCcontext *Context, ALeffectslot **start, ALsizei count);
-static void RemoveEffectSlotArray(ALCcontext *Context, const ALeffectslot *slot);
+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 UIntMap EffectStateFactoryMap;
-static inline ALeffectStateFactory *getFactoryByType(ALenum type)
+static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
{
- ALeffectStateFactory* (*getFactory)(void) = LookupUIntMapKey(&EffectStateFactoryMap, type);
- if(getFactory != NULL)
- return getFactory();
- return NULL;
+ 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, context); \
+ else \
+ ATOMIC_FLAG_CLEAR(&slot->PropsClean, almemory_order_release); \
+} while(0)
+
+
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
+ ALCdevice *device;
ALCcontext *context;
- VECTOR(ALeffectslot*) slotvec;
ALsizei cur;
- ALenum err;
context = GetContextRef();
if(!context) return;
- VECTOR_INIT(slotvec);
-
if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- if(!VECTOR_RESERVE(slotvec, n))
- SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n);
+ if(n == 0) goto done;
+ LockEffectSlotList(context);
+ device = context->Device;
for(cur = 0;cur < n;cur++)
{
- ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
- err = AL_OUT_OF_MEMORY;
- if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
+ 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++)
{
- al_free(slot);
- alDeleteAuxiliaryEffectSlots(cur, effectslots);
- SET_ERROR_AND_GOTO(context, err, done);
+ if(!*iter)
+ break;
}
-
- err = NewThunkEntry(&slot->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&context->EffectSlotMap, slot->id, slot);
- if(err != AL_NO_ERROR)
+ if(iter == end)
+ {
+ if(device->AuxiliaryEffectSlotMax == VECTOR_SIZE(context->EffectSlotList))
+ {
+ UnlockEffectSlotList(context);
+ alDeleteAuxiliaryEffectSlots(cur, effectslots);
+ SETERR_GOTO(context, AL_OUT_OF_MEMORY, done,
+ "Exceeding %u auxiliary effect slot limit", device->AuxiliaryEffectSlotMax);
+ }
+ 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)
{
- FreeThunkEntry(slot->id);
- DELETE_OBJ(slot->EffectState);
al_free(slot);
+ UnlockEffectSlotList(context);
alDeleteAuxiliaryEffectSlots(cur, effectslots);
- SET_ERROR_AND_GOTO(context, err, done);
+ SETERR_GOTO(context, err, done, "Effect slot object allocation failed");
}
+ aluInitEffectPanning(slot);
- VECTOR_PUSH_BACK(slotvec, slot);
+ slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1;
+ *iter = slot;
effectslots[cur] = slot->id;
}
- err = AddEffectSlotArray(context, VECTOR_ITER_BEGIN(slotvec), n);
- if(err != AL_NO_ERROR)
- {
- alDeleteAuxiliaryEffectSlots(cur, effectslots);
- SET_ERROR_AND_GOTO(context, err, done);
- }
+ AddActiveEffectSlots(effectslots, n, context);
+ UnlockEffectSlotList(context);
done:
- VECTOR_DEINIT(slotvec);
-
ALCcontext_DecRef(context);
}
@@ -116,31 +178,37 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *
context = GetContextRef();
if(!context) return;
+ LockEffectSlotList(context);
if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n);
+ if(n == 0) goto done;
+
for(i = 0;i < n;i++)
{
if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u",
+ effectslots[i]);
if(ReadRef(&slot->ref) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ SETERR_GOTO(context, AL_INVALID_NAME, done, "Deleting in-use effect slot %u",
+ effectslots[i]);
}
// All effectslots are valid
+ RemoveActiveEffectSlots(effectslots, n, context);
for(i = 0;i < n;i++)
{
- if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
+ if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
continue;
- FreeThunkEntry(slot->id);
+ VECTOR_ELEM(context->EffectSlotList, effectslots[i]-1) = NULL;
- RemoveEffectSlotArray(context, slot);
- DELETE_OBJ(slot->EffectState);
+ DeinitEffectSlot(slot);
memset(slot, 0, sizeof(*slot));
al_free(slot);
}
done:
+ UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@@ -152,7 +220,9 @@ AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
context = GetContextRef();
if(!context) return AL_FALSE;
+ LockEffectSlotList(context);
ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
+ UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
@@ -170,35 +240,45 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
context = GetContextRef();
if(!context) return;
- device = context->Device;
+ 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;
+
+ LockEffectList(device);
effect = (value ? LookupEffect(device, value) : NULL);
if(!(value == 0 || effect != NULL))
- 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(context, slot, effect);
+ UnlockEffectList(device);
- err = InitializeEffect(device, slot, effect);
if(err != AL_NO_ERROR)
- SET_ERROR_AND_GOTO(context, err, done);
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
+ 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;
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
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:
+ UnlockEffectSlotList(context);
+ almtx_unlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -217,15 +297,18 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para
context = GetContextRef();
if(!context) return;
+ 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:
+ UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@@ -237,23 +320,27 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param
context = GetContextRef();
if(!context) return;
+ 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;
- ATOMIC_STORE(&slot->NeedsUpdate, AL_TRUE);
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:
+ UnlockEffectSlotList(context);
+ almtx_unlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -271,15 +358,18 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para
context = GetContextRef();
if(!context) return;
+ 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:
+ UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@@ -291,8 +381,9 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa
context = GetContextRef();
if(!context) return;
+ 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:
@@ -300,10 +391,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:
+ UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@@ -322,15 +414,18 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p
context = GetContextRef();
if(!context) return;
+ 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:
+ UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@@ -342,8 +437,9 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa
context = GetContextRef();
if(!context) return;
+ 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:
@@ -351,10 +447,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:
+ UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
@@ -372,82 +469,32 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p
context = GetContextRef();
if(!context) return;
+ 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:
+ UnlockEffectSlotList(context);
ALCcontext_DecRef(context);
}
-static ALenum AddEffectSlotArray(ALCcontext *context, ALeffectslot **start, ALsizei count)
-{
- ALenum err = AL_NO_ERROR;
-
- LockContext(context);
- if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_ITER_END(context->ActiveAuxSlots), start, start+count))
- err = AL_OUT_OF_MEMORY;
- UnlockContext(context);
-
- return err;
-}
-
-static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot)
-{
- ALeffectslot **iter;
-
- LockContext(context);
-#define MATCH_SLOT(_i) (slot == *(_i))
- VECTOR_FIND_IF(iter, ALeffectslot*, context->ActiveAuxSlots, MATCH_SLOT);
- if(iter != VECTOR_ITER_END(context->ActiveAuxSlots))
- {
- *iter = VECTOR_BACK(context->ActiveAuxSlots);
- VECTOR_POP_BACK(context->ActiveAuxSlots);
- }
-#undef MATCH_SLOT
- UnlockContext(context);
-}
-
-
-void InitEffectFactoryMap(void)
-{
- InitUIntMap(&EffectStateFactoryMap, ~0);
-
- InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_NULL, ALnullStateFactory_getFactory);
- InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory);
- InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_REVERB, ALreverbStateFactory_getFactory);
- InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_AUTOWAH, ALautowahStateFactory_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);
- ALeffectStateFactory *factory;
+ struct ALeffectslotProps *props;
+ ALeffectState *State;
- if(newtype != EffectSlot->EffectType)
+ if(newtype != EffectSlot->Effect.Type)
{
- ALeffectState *State;
- FPUCtl oldMode;
+ EffectStateFactory *factory;
factory = getFactoryByType(newtype);
if(!factory)
@@ -455,96 +502,301 @@ 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)();
- if(!State)
- return AL_OUT_OF_MEMORY;
-
- SetMixerFPUMode(&oldMode);
+ State = EffectStateFactory_create(factory);
+ if(!State) return AL_OUT_OF_MEMORY;
- ALCdevice_Lock(Device);
+ START_MIXER_MODE();
+ almtx_lock(&Device->BackendLock);
+ State->OutBuffer = Device->Dry.Buffer;
+ State->OutChannels = Device->Dry.NumChannels;
if(V(State,deviceUpdate)(Device) == AL_FALSE)
{
- ALCdevice_Unlock(Device);
- RestoreFPUMode(&oldMode);
- DELETE_OBJ(State);
+ almtx_unlock(&Device->BackendLock);
+ LEAVE_MIXER_MODE();
+ ALeffectState_DecRef(State);
return AL_OUT_OF_MEMORY;
}
+ almtx_unlock(&Device->BackendLock);
+ END_MIXER_MODE();
- State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
if(!effect)
{
- memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps));
- EffectSlot->EffectType = AL_EFFECT_NULL;
+ EffectSlot->Effect.Type = AL_EFFECT_NULL;
+ memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props));
}
else
{
- memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
- EffectSlot->EffectType = effect->type;
+ EffectSlot->Effect.Type = effect->type;
+ EffectSlot->Effect.Props = effect->Props;
}
- /* FIXME: This should be done asynchronously, but since the EffectState
- * object was changed, it needs an update before its Process method can
- * be called. */
- ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_FALSE);
- V(EffectSlot->EffectState,update)(Device, EffectSlot);
- ALCdevice_Unlock(Device);
+ ALeffectState_DecRef(EffectSlot->Effect.State);
+ EffectSlot->Effect.State = State;
+ }
+ else if(effect)
+ EffectSlot->Effect.Props = effect->Props;
+
+ /* Remove state references from old effect slot property updates. */
+ props = ATOMIC_LOAD_SEQ(&Context->FreeEffectslotProps);
+ while(props)
+ {
+ if(props->State)
+ ALeffectState_DecRef(props->State);
+ props->State = NULL;
+ props = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
+ }
+
+ return AL_NO_ERROR;
+}
- RestoreFPUMode(&oldMode);
- DELETE_OBJ(State);
- State = NULL;
+static void ALeffectState_IncRef(ALeffectState *state)
+{
+ uint ref;
+ ref = IncrementRef(&state->Ref);
+ TRACEREF("%p increasing refcount to %u\n", state, ref);
+}
+
+void ALeffectState_DecRef(ALeffectState *state)
+{
+ uint ref;
+ ref = DecrementRef(&state->Ref);
+ TRACEREF("%p decreasing refcount to %u\n", state, ref);
+ if(ref == 0) DELETE_OBJ(state);
+}
+
+
+void ALeffectState_Construct(ALeffectState *state)
+{
+ InitRef(&state->Ref, 1);
+
+ state->OutBuffer = NULL;
+ state->OutChannels = 0;
+}
+
+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;
+ }
+ }
}
- else
+
+ /* Reallocate newarray if the new size ended up smaller from duplicate
+ * removal.
+ */
+ if(UNLIKELY(newcount < newarray->count))
{
- if(effect)
+ 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;)
{
- ALCdevice_Lock(Device);
- memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
- ALCdevice_Unlock(Device);
- ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_TRUE);
+ if(slot->id == slotids[--j])
+ goto skip_ins;
}
+ newarray->slot[newarray->count++] = slot;
+ skip_ins: ;
}
- return AL_NO_ERROR;
+ /* 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;
- ALuint i, c;
+ EffectStateFactory *factory;
- slot->EffectType = AL_EFFECT_NULL;
+ slot->Effect.Type = AL_EFFECT_NULL;
factory = getFactoryByType(AL_EFFECT_NULL);
- if(!(slot->EffectState=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;
- ATOMIC_INIT(&slot->NeedsUpdate, AL_FALSE);
- for(c = 0;c < 1;c++)
- {
- for(i = 0;i < BUFFERSIZE;i++)
- slot->WetBuffer[c][i] = 0.0f;
- }
+ ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_relaxed);
InitRef(&slot->ref, 0);
+ ATOMIC_INIT(&slot->Update, NULL);
+
+ slot->Params.Gain = 1.0f;
+ slot->Params.AuxSendAuto = AL_TRUE;
+ ALeffectState_IncRef(slot->Effect.State);
+ 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;
+
return AL_NO_ERROR;
}
-ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
+void DeinitEffectSlot(ALeffectslot *slot)
+{
+ struct ALeffectslotProps *props;
+
+ props = ATOMIC_LOAD_SEQ(&slot->Update);
+ if(props)
+ {
+ if(props->State) ALeffectState_DecRef(props->State);
+ TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
+ al_free(props);
+ }
+
+ ALeffectState_DecRef(slot->Effect.State);
+ if(slot->Params.EffectState)
+ ALeffectState_DecRef(slot->Params.EffectState);
+}
+
+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(&context->FreeEffectslotProps, almemory_order_relaxed);
+ if(!props)
+ props = al_calloc(16, sizeof(*props));
+ else
+ {
+ struct ALeffectslotProps *next;
+ do {
+ next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
+ } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeEffectslotProps, &props, next,
+ almemory_order_seq_cst, almemory_order_acquire) == 0);
+ }
+
+ /* Copy in current property values. */
+ props->Gain = slot->Gain;
+ props->AuxSendAuto = slot->AuxSendAuto;
+
+ props->Type = slot->Effect.Type;
+ props->Props = slot->Effect.Props;
+ /* Swap out any stale effect state object there may be in the container, to
+ * delete it.
+ */
+ ALeffectState_IncRef(slot->Effect.State);
+ oldstate = props->State;
+ props->State = slot->Effect.State;
+
+ /* Set the new container for updating internal parameters. */
+ props = ATOMIC_EXCHANGE_PTR(&slot->Update, props, almemory_order_acq_rel);
+ if(props)
+ {
+ /* If there was an unused update container, put it back in the
+ * freelist.
+ */
+ if(props->State)
+ ALeffectState_DecRef(props->State);
+ props->State = NULL;
+ ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props);
+ }
+
+ if(oldstate)
+ ALeffectState_DecRef(oldstate);
+}
+
+void UpdateAllEffectSlotProps(ALCcontext *context)
{
- ALsizei pos;
- for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
+ struct ALeffectslotArray *auxslots;
+ ALsizei i;
+
+ LockEffectSlotList(context);
+ auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire);
+ for(i = 0;i < auxslots->count;i++)
{
- ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
- Context->EffectSlotMap.array[pos].value = NULL;
+ ALeffectslot *slot = auxslots->slot[i];
+ if(!ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel))
+ UpdateEffectSlotProps(slot, context);
+ }
+ UnlockEffectSlotList(context);
+}
+
+ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context)
+{
+ ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList);
+ ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList);
+ size_t leftover = 0;
- DELETE_OBJ(temp->EffectState);
+ for(;iter != end;iter++)
+ {
+ ALeffectslot *slot = *iter;
+ if(!slot) continue;
+ *iter = NULL;
- FreeThunkEntry(temp->id);
- memset(temp, 0, sizeof(ALeffectslot));
- al_free(temp);
+ DeinitEffectSlot(slot);
+
+ memset(slot, 0, sizeof(*slot));
+ al_free(slot);
+ ++leftover;
}
+ if(leftover > 0)
+ WARN("(%p) Deleted "SZFMT" AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s");
}
diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c
index 904fd61d..ed712434 100644
--- a/OpenAL32/alBuffer.c
+++ b/OpenAL32/alBuffer.c
@@ -32,20 +32,41 @@
#include "alu.h"
#include "alError.h"
#include "alBuffer.h"
-#include "alThunk.h"
#include "sample_cvt.h"
-extern inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id);
-extern inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id);
-extern inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type);
-extern inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type);
+extern inline void LockBufferList(ALCdevice *device);
+extern inline void UnlockBufferList(ALCdevice *device);
+extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type);
+extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type);
-static ALboolean IsValidType(ALenum type) DECL_CONST;
-static ALboolean IsValidChannels(ALenum channels) DECL_CONST;
-static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type) DECL_CONST;
-static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type) DECL_CONST;
-static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align);
+static ALbuffer *AllocBuffer(ALCcontext *context);
+static void FreeBuffer(ALCdevice *device, ALbuffer *buffer);
+static const ALchar *NameFromUserFmtType(enum UserFmtType type);
+static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei size,
+ enum UserFmtChannels SrcChannels, enum UserFmtType SrcType,
+ const ALvoid *data, ALbitfieldSOFT access);
+static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type);
+static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align);
+
+static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
+{
+ BufferSubList *sublist;
+ ALuint lidx = (id-1) >> 6;
+ ALsizei slidx = (id-1) & 0x3f;
+
+ if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList)))
+ return NULL;
+ sublist = &VECTOR_ELEM(device->BufferList, lidx);
+ if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
+ return NULL;
+ return sublist->Buffers + slidx;
+}
+
+
+#define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
+#define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT)
+#define INVALID_MAP_FLAGS ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
@@ -57,11 +78,10 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
if(!context) return;
if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- for(cur = 0;cur < n;cur++)
+ alSetError(context, AL_INVALID_VALUE, "Generating %d buffers", n);
+ else for(cur = 0;cur < n;cur++)
{
- ALbuffer *buffer = NewBuffer(context);
+ ALbuffer *buffer = AllocBuffer(context);
if(!buffer)
{
alDeleteBuffers(cur, buffers);
@@ -71,7 +91,6 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
buffers[cur] = buffer->id;
}
-done:
ALCcontext_DecRef(context);
}
@@ -85,29 +104,40 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
context = GetContextRef();
if(!context) return;
- if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
device = context->Device;
+
+ LockBufferList(device);
+ if(UNLIKELY(n < 0))
+ {
+ alSetError(context, AL_INVALID_VALUE, "Deleting %d buffers", n);
+ goto done;
+ }
+
for(i = 0;i < n;i++)
{
if(!buffers[i])
continue;
- /* Check for valid Buffer ID */
+ /* Check for valid Buffer ID, and make sure it's not in use. */
if((ALBuf=LookupBuffer(device, buffers[i])) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ {
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffers[i]);
+ goto done;
+ }
if(ReadRef(&ALBuf->ref) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ {
+ alSetError(context, AL_INVALID_OPERATION, "Deleting in-use buffer %u", buffers[i]);
+ goto done;
+ }
}
-
for(i = 0;i < n;i++)
{
if((ALBuf=LookupBuffer(device, buffers[i])) != NULL)
- DeleteBuffer(device, ALBuf);
+ FreeBuffer(device, ALBuf);
}
done:
+ UnlockBufferList(device);
ALCcontext_DecRef(context);
}
@@ -119,8 +149,10 @@ AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
context = GetContextRef();
if(!context) return AL_FALSE;
+ LockBufferList(context->Device);
ret = ((!buffer || LookupBuffer(context->Device, buffer)) ?
AL_TRUE : AL_FALSE);
+ UnlockBufferList(context->Device);
ALCcontext_DecRef(context);
@@ -129,389 +161,297 @@ AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
+{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); }
+
+AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags)
{
- enum UserFmtChannels srcchannels;
- enum UserFmtType srctype;
+ enum UserFmtChannels srcchannels = UserFmtMono;
+ enum UserFmtType srctype = UserFmtUByte;
ALCdevice *device;
ALCcontext *context;
ALbuffer *albuf;
- ALenum newformat = AL_NONE;
- ALuint framesize;
- ALsizei align;
- ALenum err;
context = GetContextRef();
if(!context) return;
device = context->Device;
- if((albuf=LookupBuffer(device, buffer)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(!(size >= 0 && freq > 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
-
- align = ATOMIC_LOAD(&albuf->UnpackAlign);
- if(SanitizeAlignment(srctype, &align) == AL_FALSE)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- switch(srctype)
- {
- case UserFmtByte:
- case UserFmtUByte:
- case UserFmtShort:
- case UserFmtUShort:
- case UserFmtFloat:
- framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
- if((size%framesize) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- err = LoadData(albuf, freq, format, size/framesize*align,
- srcchannels, srctype, data, align, AL_TRUE);
- if(err != AL_NO_ERROR)
- SET_ERROR_AND_GOTO(context, err, done);
- break;
-
- case UserFmtInt:
- case UserFmtUInt:
- case UserFmtByte3:
- case UserFmtUByte3:
- case UserFmtDouble:
- framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
- if((size%framesize) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- switch(srcchannels)
- {
- case UserFmtMono: newformat = AL_FORMAT_MONO_FLOAT32; break;
- case UserFmtStereo: newformat = AL_FORMAT_STEREO_FLOAT32; break;
- case UserFmtRear: newformat = AL_FORMAT_REAR32; break;
- case UserFmtQuad: newformat = AL_FORMAT_QUAD32; break;
- case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
- case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
- case UserFmtX71: newformat = AL_FORMAT_71CHN32; break;
- case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_FLOAT32; break;
- case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_FLOAT32; break;
- }
- err = LoadData(albuf, freq, newformat, size/framesize*align,
- srcchannels, srctype, data, align, AL_TRUE);
- if(err != AL_NO_ERROR)
- SET_ERROR_AND_GOTO(context, err, done);
- break;
-
- case UserFmtMulaw:
- case UserFmtAlaw:
- framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
- if((size%framesize) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- switch(srcchannels)
- {
- case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
- case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
- case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
- case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
- case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
- case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
- case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
- case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
- case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
- }
- err = LoadData(albuf, freq, newformat, size/framesize*align,
- srcchannels, srctype, data, align, AL_TRUE);
- if(err != AL_NO_ERROR)
- SET_ERROR_AND_GOTO(context, err, done);
- break;
+ LockBufferList(device);
+ if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(size < 0))
+ alSetError(context, AL_INVALID_VALUE, "Negative storage size %d", size);
+ else if(UNLIKELY(freq < 1))
+ alSetError(context, AL_INVALID_VALUE, "Invalid sample rate %d", freq);
+ else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0))
+ alSetError(context, AL_INVALID_VALUE, "Invalid storage flags 0x%x",
+ flags&INVALID_STORAGE_MASK);
+ else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS)))
+ alSetError(context, AL_INVALID_VALUE,
+ "Declaring persistently mapped storage without read or write access");
+ else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE))
+ alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format);
+ else
+ LoadData(context, albuf, freq, size, srcchannels, srctype, data, flags);
- case UserFmtIMA4:
- framesize = (align-1)/2 + 4;
- framesize *= ChannelsFromUserFmt(srcchannels);
- if((size%framesize) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ UnlockBufferList(device);
+ ALCcontext_DecRef(context);
+}
- switch(srcchannels)
- {
- case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
- case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
- case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
- case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
- case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
- case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
- case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
- case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
- case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
- }
- err = LoadData(albuf, freq, newformat, size/framesize*align,
- srcchannels, srctype, data, align, AL_TRUE);
- if(err != AL_NO_ERROR)
- SET_ERROR_AND_GOTO(context, err, done);
- break;
+AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access)
+{
+ void *retval = NULL;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALbuffer *albuf;
- case UserFmtMSADPCM:
- framesize = (align-2)/2 + 7;
- framesize *= ChannelsFromUserFmt(srcchannels);
- if((size%framesize) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ context = GetContextRef();
+ if(!context) return retval;
- switch(srcchannels)
- {
- case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
- case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
- case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
- case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
- case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
- case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
- case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
- case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
- case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
- }
- err = LoadData(albuf, freq, newformat, size/framesize*align,
- srcchannels, srctype, data, align, AL_TRUE);
- if(err != AL_NO_ERROR)
- SET_ERROR_AND_GOTO(context, err, done);
- break;
+ device = context->Device;
+ LockBufferList(device);
+ if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0))
+ alSetError(context, AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS);
+ else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS)))
+ alSetError(context, AL_INVALID_VALUE, "Mapping buffer %u without read or write access",
+ buffer);
+ else
+ {
+ ALbitfieldSOFT unavailable = (albuf->Access^access) & access;
+ if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)))
+ alSetError(context, AL_INVALID_OPERATION,
+ "Mapping in-use buffer %u without persistent mapping", buffer);
+ else if(UNLIKELY(albuf->MappedAccess != 0))
+ alSetError(context, AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer);
+ else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT)))
+ alSetError(context, AL_INVALID_VALUE,
+ "Mapping buffer %u for reading without read access", buffer);
+ else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT)))
+ alSetError(context, AL_INVALID_VALUE,
+ "Mapping buffer %u for writing without write access", buffer);
+ else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT)))
+ alSetError(context, AL_INVALID_VALUE,
+ "Mapping buffer %u persistently without persistent access", buffer);
+ else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize ||
+ length <= 0 || length > albuf->OriginalSize - offset))
+ alSetError(context, AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u",
+ offset, length, buffer);
+ else
+ {
+ retval = (ALbyte*)albuf->data + offset;
+ albuf->MappedAccess = access;
+ albuf->MappedOffset = offset;
+ albuf->MappedSize = length;
+ }
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
+ return retval;
}
-AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
+AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer)
{
- enum UserFmtChannels srcchannels;
- enum UserFmtType srctype;
ALCdevice *device;
ALCcontext *context;
ALbuffer *albuf;
- ALuint byte_align;
- ALuint channels;
- ALuint bytes;
- ALsizei align;
context = GetContextRef();
if(!context) return;
device = context->Device;
+ LockBufferList(device);
if((albuf=LookupBuffer(device, buffer)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(!(length >= 0 && offset >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
-
- WriteLock(&albuf->lock);
- align = ATOMIC_LOAD(&albuf->UnpackAlign);
- if(SanitizeAlignment(srctype, &align) == AL_FALSE)
- {
- WriteUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- }
- if(srcchannels != albuf->OriginalChannels || srctype != albuf->OriginalType)
- {
- WriteUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- }
- if(align != albuf->OriginalAlign)
- {
- WriteUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- }
-
- if(albuf->OriginalType == UserFmtIMA4)
- {
- byte_align = (albuf->OriginalAlign-1)/2 + 4;
- byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
- }
- else if(albuf->OriginalType == UserFmtMSADPCM)
- {
- byte_align = (albuf->OriginalAlign-2)/2 + 7;
- byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
- }
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(albuf->MappedAccess == 0)
+ alSetError(context, AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer);
else
{
- byte_align = albuf->OriginalAlign;
- byte_align *= FrameSizeFromUserFmt(albuf->OriginalChannels,
- albuf->OriginalType);
- }
-
- if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset ||
- (offset%byte_align) != 0 || (length%byte_align) != 0)
- {
- WriteUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ albuf->MappedAccess = 0;
+ albuf->MappedOffset = 0;
+ albuf->MappedSize = 0;
}
+ UnlockBufferList(device);
- channels = ChannelsFromFmt(albuf->FmtChannels);
- bytes = BytesFromFmt(albuf->FmtType);
- /* offset -> byte offset, length -> sample count */
- offset = offset/byte_align * channels*bytes;
- length = length/byte_align * albuf->OriginalAlign;
-
- ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
- data, srctype, channels, length, align);
- WriteUnlock(&albuf->lock);
-
-done:
ALCcontext_DecRef(context);
}
-
-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 alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length)
{
ALCdevice *device;
ALCcontext *context;
ALbuffer *albuf;
- ALsizei align;
- ALenum err;
context = GetContextRef();
if(!context) return;
device = context->Device;
- if((albuf=LookupBuffer(device, buffer)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(!(samples >= 0 && samplerate != 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
-
- align = ATOMIC_LOAD(&albuf->UnpackAlign);
- if(SanitizeAlignment(type, &align) == AL_FALSE)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- if((samples%align) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- err = LoadData(albuf, samplerate, internalformat, samples,
- channels, type, data, align, AL_FALSE);
- if(err != AL_NO_ERROR)
- SET_ERROR_AND_GOTO(context, err, done);
+ LockBufferList(device);
+ if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)))
+ alSetError(context, AL_INVALID_OPERATION,
+ "Flushing buffer %u while not mapped for writing", buffer);
+ else if(UNLIKELY(offset < albuf->MappedOffset ||
+ offset >= albuf->MappedOffset+albuf->MappedSize ||
+ length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset))
+ alSetError(context, AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u",
+ offset, length, buffer);
+ else
+ {
+ /* FIXME: Need to use some method of double-buffering for the mixer and
+ * app to hold separate memory, which can be safely transfered
+ * asynchronously. Currently we just say the app shouldn't write where
+ * OpenAL's reading, and hope for the best...
+ */
+ ATOMIC_THREAD_FENCE(almemory_order_seq_cst);
+ }
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
-AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
- ALsizei offset, ALsizei samples,
- ALenum channels, ALenum type, const ALvoid *data)
+AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
{
+ enum UserFmtChannels srcchannels = UserFmtMono;
+ enum UserFmtType srctype = UserFmtUByte;
ALCdevice *device;
ALCcontext *context;
ALbuffer *albuf;
- ALsizei align;
context = GetContextRef();
if(!context) return;
device = context->Device;
- if((albuf=LookupBuffer(device, buffer)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(!(samples >= 0 && offset >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- if(IsValidType(type) == AL_FALSE)
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
-
- WriteLock(&albuf->lock);
- align = ATOMIC_LOAD(&albuf->UnpackAlign);
- if(SanitizeAlignment(type, &align) == AL_FALSE)
- {
- WriteUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- }
- if(channels != (ALenum)albuf->FmtChannels)
- {
- WriteUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- }
- if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
- {
- WriteUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- }
- if((samples%align) != 0)
+ LockBufferList(device);
+ if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE))
+ alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format);
+ else
{
- WriteUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ ALsizei unpack_align, align;
+ ALsizei byte_align;
+ ALsizei frame_size;
+ ALsizei num_chans;
+ void *dst;
+
+ unpack_align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
+ align = SanitizeAlignment(srctype, unpack_align);
+ if(UNLIKELY(align < 1))
+ alSetError(context, AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align);
+ else if(UNLIKELY((long)srcchannels != (long)albuf->FmtChannels ||
+ srctype != albuf->OriginalType))
+ alSetError(context, AL_INVALID_ENUM, "Unpacking data with mismatched format");
+ else if(UNLIKELY(align != albuf->OriginalAlign))
+ alSetError(context, AL_INVALID_VALUE,
+ "Unpacking data with alignment %u does not match original alignment %u",
+ align, albuf->OriginalAlign);
+ else if(UNLIKELY(albuf->MappedAccess != 0))
+ alSetError(context, AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u",
+ buffer);
+ else
+ {
+ num_chans = ChannelsFromFmt(albuf->FmtChannels);
+ frame_size = num_chans * BytesFromFmt(albuf->FmtType);
+ if(albuf->OriginalType == UserFmtIMA4)
+ byte_align = ((align-1)/2 + 4) * num_chans;
+ else if(albuf->OriginalType == UserFmtMSADPCM)
+ byte_align = ((align-2)/2 + 7) * num_chans;
+ else
+ byte_align = align * frame_size;
+
+ if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize ||
+ length > albuf->OriginalSize-offset))
+ alSetError(context, AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u",
+ offset, length, buffer);
+ else if(UNLIKELY((offset%byte_align) != 0))
+ alSetError(context, AL_INVALID_VALUE,
+ "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)",
+ offset, byte_align, align);
+ else if(UNLIKELY((length%byte_align) != 0))
+ alSetError(context, AL_INVALID_VALUE,
+ "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)",
+ length, byte_align, align);
+ else
+ {
+ /* offset -> byte offset, length -> sample count */
+ offset = offset/byte_align * align * frame_size;
+ length = length/byte_align * align;
+
+ dst = (ALbyte*)albuf->data + offset;
+ if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort)
+ Convert_ALshort_ALima4(dst, data, num_chans, length, align);
+ else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort)
+ Convert_ALshort_ALmsadpcm(dst, data, num_chans, length, align);
+ else
+ {
+ assert((long)srctype == (long)albuf->FmtType);
+ memcpy(dst, data, length*frame_size);
+ }
+ }
+ }
}
+ UnlockBufferList(device);
- /* offset -> byte offset */
- offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
- ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
- data, type, ChannelsFromFmt(albuf->FmtChannels), samples, align);
- WriteUnlock(&albuf->lock);
+ ALCcontext_DecRef(context);
+}
+
+
+AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint UNUSED(buffer),
+ ALuint UNUSED(samplerate), ALenum UNUSED(internalformat), ALsizei UNUSED(samples),
+ ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data))
+{
+ ALCcontext *context;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ alSetError(context, AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported");
-done:
ALCcontext_DecRef(context);
}
-AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
- ALsizei offset, ALsizei samples,
- ALenum channels, ALenum type, ALvoid *data)
+AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint UNUSED(buffer),
+ ALsizei UNUSED(offset), ALsizei UNUSED(samples),
+ ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data))
{
- ALCdevice *device;
ALCcontext *context;
- ALbuffer *albuf;
- ALsizei align;
context = GetContextRef();
if(!context) return;
- device = context->Device;
- if((albuf=LookupBuffer(device, buffer)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(!(samples >= 0 && offset >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- if(IsValidType(type) == AL_FALSE)
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
-
- ReadLock(&albuf->lock);
- align = ATOMIC_LOAD(&albuf->PackAlign);
- if(SanitizeAlignment(type, &align) == AL_FALSE)
- {
- ReadUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- }
- if(channels != (ALenum)albuf->FmtChannels)
- {
- ReadUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- }
- if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
- {
- ReadUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- }
- if((samples%align) != 0)
- {
- ReadUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- }
+ alSetError(context, AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported");
- /* offset -> byte offset */
- offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
- ConvertData(data, type, (char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
- ChannelsFromFmt(albuf->FmtChannels), samples, align);
- ReadUnlock(&albuf->lock);
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint UNUSED(buffer),
+ ALsizei UNUSED(offset), ALsizei UNUSED(samples),
+ ALenum UNUSED(channels), ALenum UNUSED(type), ALvoid *UNUSED(data))
+{
+ ALCcontext *context;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ alSetError(context, AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported");
-done:
ALCcontext_DecRef(context);
}
-AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format)
+AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format))
{
- enum FmtChannels dstchannels;
- enum FmtType dsttype;
ALCcontext *context;
- ALboolean ret;
context = GetContextRef();
if(!context) return AL_FALSE;
- ret = DecomposeFormat(format, &dstchannels, &dsttype);
+ alSetError(context, AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported");
ALCcontext_DecRef(context);
-
- return ret;
+ return AL_FALSE;
}
@@ -524,16 +464,16 @@ AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(va
if(!context) return;
device = context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else switch(param)
{
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -547,16 +487,16 @@ AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(v
if(!context) return;
device = context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else switch(param)
{
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -570,18 +510,18 @@ AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *v
if(!context) return;
device = context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- if(!(values))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(!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 buffer float-vector property 0x%04x", param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -596,28 +536,30 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
if(!context) return;
device = context->Device;
- if((albuf=LookupBuffer(device, buffer)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else switch(param)
{
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
- if(!(value >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- ATOMIC_STORE(&albuf->UnpackAlign, value);
+ if(UNLIKELY(value < 0))
+ alSetError(context, AL_INVALID_VALUE, "Invalid unpack block alignment %d", value);
+ else
+ ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value);
break;
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
- if(!(value >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- ATOMIC_STORE(&albuf->PackAlign, value);
+ if(UNLIKELY(value < 0))
+ alSetError(context, AL_INVALID_VALUE, "Invalid pack block alignment %d", value);
+ else
+ ATOMIC_STORE_SEQ(&albuf->PackAlign, value);
break;
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -631,16 +573,16 @@ AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(val
if(!context) return;
device = context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else switch(param)
{
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -666,37 +608,33 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val
if(!context) return;
device = context->Device;
- if((albuf=LookupBuffer(device, buffer)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- if(!(values))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(!values))
+ alSetError(context, AL_INVALID_VALUE, "NULL pointer");
+ else switch(param)
{
case AL_LOOP_POINTS_SOFT:
- WriteLock(&albuf->lock);
- if(ReadRef(&albuf->ref) != 0)
- {
- WriteUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
- }
- if(values[0] >= values[1] || values[0] < 0 ||
- values[1] > albuf->SampleLen)
+ if(UNLIKELY(ReadRef(&albuf->ref) != 0))
+ alSetError(context, AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points",
+ buffer);
+ else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen))
+ alSetError(context, AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u",
+ values[0], values[1], buffer);
+ else
{
- WriteUnlock(&albuf->lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ albuf->LoopStart = values[0];
+ albuf->LoopEnd = values[1];
}
-
- albuf->LoopStart = values[0];
- albuf->LoopEnd = values[1];
- WriteUnlock(&albuf->lock);
break;
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x",
+ param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -711,27 +649,18 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val
if(!context) return;
device = context->Device;
- if((albuf=LookupBuffer(device, buffer)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- if(!(value))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(!value))
+ alSetError(context, AL_INVALID_VALUE, "NULL pointer");
+ else switch(param)
{
- case AL_SEC_LENGTH_SOFT:
- ReadLock(&albuf->lock);
- if(albuf->SampleLen != 0)
- *value = albuf->SampleLen / (ALfloat)albuf->Frequency;
- else
- *value = 0.0f;
- ReadUnlock(&albuf->lock);
- break;
-
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -745,18 +674,18 @@ AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *valu
if(!context) return;
device = context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- if(!(value1 && value2 && value3))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(!value1 || !value2 || !value3))
+ 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 buffer 3-float property 0x%04x", param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -777,18 +706,18 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu
if(!context) return;
device = context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- if(!(values))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(!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 buffer float-vector property 0x%04x", param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -803,12 +732,12 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value
if(!context) return;
device = context->Device;
- if((albuf=LookupBuffer(device, buffer)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- if(!(value))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(!value))
+ alSetError(context, AL_INVALID_VALUE, "NULL pointer");
+ else switch(param)
{
case AL_FREQUENCY:
*value = albuf->Frequency;
@@ -823,37 +752,23 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value
break;
case AL_SIZE:
- ReadLock(&albuf->lock);
*value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
albuf->FmtType);
- ReadUnlock(&albuf->lock);
- break;
-
- case AL_INTERNAL_FORMAT_SOFT:
- *value = albuf->Format;
- break;
-
- case AL_BYTE_LENGTH_SOFT:
- *value = albuf->OriginalSize;
- break;
-
- case AL_SAMPLE_LENGTH_SOFT:
- *value = albuf->SampleLen;
break;
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
- *value = ATOMIC_LOAD(&albuf->UnpackAlign);
+ *value = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
break;
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
- *value = ATOMIC_LOAD(&albuf->PackAlign);
+ *value = ATOMIC_LOAD_SEQ(&albuf->PackAlign);
break;
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -867,18 +782,18 @@ AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1
if(!context) return;
device = context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- if(!(value1 && value2 && value3))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(!value1 || !value2 || !value3))
+ 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 buffer 3-integer property 0x%04x", param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
@@ -908,133 +823,214 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values
if(!context) return;
device = context->Device;
- if((albuf=LookupBuffer(device, buffer)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
-
- if(!(values))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- switch(param)
+ LockBufferList(device);
+ if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
+ alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
+ else if(UNLIKELY(!values))
+ alSetError(context, AL_INVALID_VALUE, "NULL pointer");
+ else switch(param)
{
case AL_LOOP_POINTS_SOFT:
- ReadLock(&albuf->lock);
values[0] = albuf->LoopStart;
values[1] = albuf->LoopEnd;
- ReadUnlock(&albuf->lock);
break;
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x",
+ param);
}
+ UnlockBufferList(device);
-done:
ALCcontext_DecRef(context);
}
+static const ALchar *NameFromUserFmtType(enum UserFmtType type)
+{
+ switch(type)
+ {
+ case UserFmtUByte: return "Unsigned Byte";
+ case UserFmtShort: return "Signed Short";
+ case UserFmtFloat: return "Float32";
+ case UserFmtDouble: return "Float64";
+ case UserFmtMulaw: return "muLaw";
+ case UserFmtAlaw: return "aLaw";
+ case UserFmtIMA4: return "IMA4 ADPCM";
+ case UserFmtMSADPCM: return "MSADPCM";
+ }
+ return "<internal type error>";
+}
+
/*
* LoadData
*
- * Loads the specified data into the buffer, using the specified formats.
- * Currently, the new format must have the same channel configuration as the
- * original format.
+ * Loads the specified data into the buffer, using the specified format.
*/
-ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc)
+static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALbitfieldSOFT access)
{
- ALuint NewChannels, NewBytes;
- enum FmtChannels DstChannels;
- enum FmtType DstType;
- ALuint64 newsize;
- ALvoid *temp;
-
- if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE ||
- (long)SrcChannels != (long)DstChannels)
- return AL_INVALID_ENUM;
-
- NewChannels = ChannelsFromFmt(DstChannels);
- NewBytes = BytesFromFmt(DstType);
-
- newsize = frames;
- newsize *= NewBytes;
- newsize *= NewChannels;
- if(newsize > INT_MAX)
- return AL_OUT_OF_MEMORY;
-
- WriteLock(&ALBuf->lock);
- if(ReadRef(&ALBuf->ref) != 0)
+ enum FmtChannels DstChannels = FmtMono;
+ enum FmtType DstType = FmtUByte;
+ ALsizei NumChannels, FrameSize;
+ ALsizei SrcByteAlign;
+ ALsizei unpackalign;
+ ALsizei newsize;
+ ALsizei frames;
+ ALsizei align;
+
+ if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0))
+ SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u",
+ ALBuf->id);
+
+ /* Currently no channel configurations need to be converted. */
+ switch(SrcChannels)
+ {
+ case UserFmtMono: DstChannels = FmtMono; break;
+ case UserFmtStereo: DstChannels = FmtStereo; break;
+ case UserFmtRear: DstChannels = FmtRear; break;
+ case UserFmtQuad: DstChannels = FmtQuad; break;
+ case UserFmtX51: DstChannels = FmtX51; break;
+ case UserFmtX61: DstChannels = FmtX61; break;
+ case UserFmtX71: DstChannels = FmtX71; break;
+ case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break;
+ case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break;
+ }
+ if(UNLIKELY((long)SrcChannels != (long)DstChannels))
+ SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid format");
+
+ /* IMA4 and MSADPCM convert to 16-bit short. */
+ switch(SrcType)
{
- WriteUnlock(&ALBuf->lock);
- return AL_INVALID_OPERATION;
+ case UserFmtUByte: DstType = FmtUByte; break;
+ case UserFmtShort: DstType = FmtShort; break;
+ case UserFmtFloat: DstType = FmtFloat; break;
+ case UserFmtDouble: DstType = FmtDouble; break;
+ case UserFmtAlaw: DstType = FmtAlaw; break;
+ case UserFmtMulaw: DstType = FmtMulaw; break;
+ case UserFmtIMA4: DstType = FmtShort; break;
+ case UserFmtMSADPCM: DstType = FmtShort; break;
}
- temp = realloc(ALBuf->data, (size_t)newsize);
- if(!temp && newsize)
+ /* TODO: Currently we can only map samples when they're not converted. To
+ * allow it would need some kind of double-buffering to hold onto a copy of
+ * the original data.
+ */
+ if((access&MAP_READ_WRITE_FLAGS))
{
- WriteUnlock(&ALBuf->lock);
- return AL_OUT_OF_MEMORY;
+ if(UNLIKELY((long)SrcType != (long)DstType))
+ SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped",
+ NameFromUserFmtType(SrcType));
}
- ALBuf->data = temp;
- if(data != NULL)
- ConvertData(ALBuf->data, (enum UserFmtType)DstType, data, SrcType, NewChannels, frames, align);
+ unpackalign = ATOMIC_LOAD_SEQ(&ALBuf->UnpackAlign);
+ if(UNLIKELY((align=SanitizeAlignment(SrcType, unpackalign)) < 1))
+ SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples",
+ unpackalign, NameFromUserFmtType(SrcType));
- if(storesrc)
+ if((access&AL_PRESERVE_DATA_BIT_SOFT))
{
- ALBuf->OriginalChannels = SrcChannels;
- ALBuf->OriginalType = SrcType;
- if(SrcType == UserFmtIMA4)
- {
- ALsizei byte_align = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels);
- ALBuf->OriginalSize = frames / align * byte_align;
- ALBuf->OriginalAlign = align;
- }
- else if(SrcType == UserFmtMSADPCM)
- {
- ALsizei byte_align = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels);
- ALBuf->OriginalSize = frames / align * byte_align;
- ALBuf->OriginalAlign = align;
- }
- else
+ /* Can only preserve data with the same format and alignment. */
+ if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType))
+ SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format");
+ if(UNLIKELY(ALBuf->OriginalAlign != align))
+ SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment");
+ }
+
+ /* Convert the input/source size in bytes to sample frames using the unpack
+ * block alignment.
+ */
+ if(SrcType == UserFmtIMA4)
+ SrcByteAlign = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels);
+ else if(SrcType == UserFmtMSADPCM)
+ SrcByteAlign = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels);
+ else
+ SrcByteAlign = align * FrameSizeFromUserFmt(SrcChannels, SrcType);
+ if(UNLIKELY((size%SrcByteAlign) != 0))
+ SETERR_RETURN(context, AL_INVALID_VALUE,,
+ "Data size %d is not a multiple of frame size %d (%d unpack alignment)",
+ size, SrcByteAlign, align);
+
+ if(UNLIKELY(size / SrcByteAlign > INT_MAX / align))
+ SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
+ "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align);
+ frames = size / SrcByteAlign * align;
+
+ /* Convert the sample frames to the number of bytes needed for internal
+ * storage.
+ */
+ NumChannels = ChannelsFromFmt(DstChannels);
+ FrameSize = NumChannels * BytesFromFmt(DstType);
+ if(UNLIKELY(frames > INT_MAX/FrameSize))
+ SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
+ "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize);
+ newsize = frames*FrameSize;
+
+ /* Round up to the next 16-byte multiple. This could reallocate only when
+ * increasing or the new size is less than half the current, but then the
+ * buffer's AL_SIZE would not be very reliable for accounting buffer memory
+ * usage, and reporting the real size could cause problems for apps that
+ * use AL_SIZE to try to get the buffer's play length.
+ */
+ if(LIKELY(newsize <= INT_MAX-15))
+ newsize = (newsize+15) & ~0xf;
+ if(newsize != ALBuf->BytesAlloc)
+ {
+ void *temp = al_malloc(16, (size_t)newsize);
+ if(UNLIKELY(!temp && newsize))
+ SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Failed to allocate %d bytes of storage",
+ newsize);
+ if((access&AL_PRESERVE_DATA_BIT_SOFT))
{
- ALBuf->OriginalSize = frames * FrameSizeFromUserFmt(SrcChannels, SrcType);
- ALBuf->OriginalAlign = 1;
+ ALsizei tocopy = mini(newsize, ALBuf->BytesAlloc);
+ if(tocopy > 0) memcpy(temp, ALBuf->data, tocopy);
}
+ al_free(ALBuf->data);
+ ALBuf->data = temp;
+ ALBuf->BytesAlloc = newsize;
+ }
+
+ if(SrcType == UserFmtIMA4)
+ {
+ assert(DstType == FmtShort);
+ if(data != NULL && ALBuf->data != NULL)
+ Convert_ALshort_ALima4(ALBuf->data, data, NumChannels, frames, align);
+ ALBuf->OriginalAlign = align;
+ }
+ else if(SrcType == UserFmtMSADPCM)
+ {
+ assert(DstType == FmtShort);
+ if(data != NULL && ALBuf->data != NULL)
+ Convert_ALshort_ALmsadpcm(ALBuf->data, data, NumChannels, frames, align);
+ ALBuf->OriginalAlign = align;
}
else
{
- ALBuf->OriginalChannels = (enum UserFmtChannels)DstChannels;
- ALBuf->OriginalType = (enum UserFmtType)DstType;
- ALBuf->OriginalSize = frames * NewBytes * NewChannels;
- ALBuf->OriginalAlign = 1;
+ assert((long)SrcType == (long)DstType);
+ if(data != NULL && ALBuf->data != NULL)
+ memcpy(ALBuf->data, data, frames*FrameSize);
+ ALBuf->OriginalAlign = 1;
}
+ ALBuf->OriginalSize = size;
+ ALBuf->OriginalType = SrcType;
ALBuf->Frequency = freq;
ALBuf->FmtChannels = DstChannels;
ALBuf->FmtType = DstType;
- ALBuf->Format = NewFormat;
+ ALBuf->Access = access;
ALBuf->SampleLen = frames;
ALBuf->LoopStart = 0;
ALBuf->LoopEnd = ALBuf->SampleLen;
-
- WriteUnlock(&ALBuf->lock);
- return AL_NO_ERROR;
}
-ALuint BytesFromUserFmt(enum UserFmtType type)
+ALsizei BytesFromUserFmt(enum UserFmtType type)
{
switch(type)
{
- case UserFmtByte: return sizeof(ALbyte);
case UserFmtUByte: return sizeof(ALubyte);
case UserFmtShort: return sizeof(ALshort);
- case UserFmtUShort: return sizeof(ALushort);
- case UserFmtInt: return sizeof(ALint);
- case UserFmtUInt: return sizeof(ALuint);
case UserFmtFloat: return sizeof(ALfloat);
case UserFmtDouble: return sizeof(ALdouble);
- case UserFmtByte3: return sizeof(ALbyte[3]);
- case UserFmtUByte3: return sizeof(ALubyte[3]);
case UserFmtMulaw: return sizeof(ALubyte);
case UserFmtAlaw: return sizeof(ALubyte);
case UserFmtIMA4: break; /* not handled here */
@@ -1042,7 +1038,7 @@ ALuint BytesFromUserFmt(enum UserFmtType type)
}
return 0;
}
-ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
+ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans)
{
switch(chans)
{
@@ -1137,17 +1133,20 @@ static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
return AL_FALSE;
}
-ALuint BytesFromFmt(enum FmtType type)
+ALsizei BytesFromFmt(enum FmtType type)
{
switch(type)
{
- case FmtByte: return sizeof(ALbyte);
+ case FmtUByte: return sizeof(ALubyte);
case FmtShort: return sizeof(ALshort);
case FmtFloat: return sizeof(ALfloat);
+ case FmtDouble: return sizeof(ALdouble);
+ case FmtMulaw: return sizeof(ALubyte);
+ case FmtAlaw: return sizeof(ALubyte);
}
return 0;
}
-ALuint ChannelsFromFmt(enum FmtChannels chans)
+ALsizei ChannelsFromFmt(enum FmtChannels chans)
{
switch(chans)
{
@@ -1163,73 +1162,13 @@ ALuint ChannelsFromFmt(enum FmtChannels chans)
}
return 0;
}
-static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type)
-{
- static const struct {
- ALenum format;
- enum FmtChannels channels;
- enum FmtType type;
- } list[] = {
- { AL_MONO8_SOFT, FmtMono, FmtByte },
- { AL_MONO16_SOFT, FmtMono, FmtShort },
- { AL_MONO32F_SOFT, FmtMono, FmtFloat },
-
- { AL_STEREO8_SOFT, FmtStereo, FmtByte },
- { AL_STEREO16_SOFT, FmtStereo, FmtShort },
- { AL_STEREO32F_SOFT, FmtStereo, FmtFloat },
-
- { AL_REAR8_SOFT, FmtRear, FmtByte },
- { AL_REAR16_SOFT, FmtRear, FmtShort },
- { AL_REAR32F_SOFT, FmtRear, FmtFloat },
- { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte },
- { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort },
-
- { AL_QUAD8_SOFT, FmtQuad, FmtByte },
- { AL_QUAD16_SOFT, FmtQuad, FmtShort },
- { AL_QUAD32F_SOFT, FmtQuad, FmtFloat },
-
- { AL_5POINT1_8_SOFT, FmtX51, FmtByte },
- { AL_5POINT1_16_SOFT, FmtX51, FmtShort },
- { AL_5POINT1_32F_SOFT, FmtX51, FmtFloat },
-
- { AL_6POINT1_8_SOFT, FmtX61, FmtByte },
- { AL_6POINT1_16_SOFT, FmtX61, FmtShort },
- { AL_6POINT1_32F_SOFT, FmtX61, FmtFloat },
-
- { AL_7POINT1_8_SOFT, FmtX71, FmtByte },
- { AL_7POINT1_16_SOFT, FmtX71, FmtShort },
- { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat },
-
- { AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtByte },
- { AL_FORMAT_BFORMAT2D_16, FmtBFormat2D, FmtShort },
- { AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat },
-
- { AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtByte },
- { AL_FORMAT_BFORMAT3D_16, FmtBFormat3D, FmtShort },
- { AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat },
- };
- ALuint i;
-
- for(i = 0;i < COUNTOF(list);i++)
- {
- if(list[i].format == format)
- {
- *chans = list[i].channels;
- *type = list[i].type;
- return AL_TRUE;
- }
- }
-
- return AL_FALSE;
-}
-
-static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align)
+static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align)
{
- if(*align < 0)
- return AL_FALSE;
+ if(align < 0)
+ return 0;
- if(*align == 0)
+ if(align == 0)
{
if(type == UserFmtIMA4)
{
@@ -1237,103 +1176,101 @@ static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align)
* nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
* Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
*/
- *align = 65;
+ return 65;
}
- else if(type == UserFmtMSADPCM)
- *align = 64;
- else
- *align = 1;
- return AL_TRUE;
+ if(type == UserFmtMSADPCM)
+ return 64;
+ return 1;
}
if(type == UserFmtIMA4)
{
/* IMA4 block alignment must be a multiple of 8, plus 1. */
- return ((*align)&7) == 1;
+ if((align&7) == 1) return align;
+ return 0;
}
if(type == UserFmtMSADPCM)
{
/* MSADPCM block alignment must be a multiple of 2. */
- /* FIXME: Too strict? Might only require align*channels to be a
- * multiple of 2. */
- return ((*align)&1) == 0;
+ if((align&1) == 0) return align;
+ return 0;
}
- return AL_TRUE;
+ return align;
}
-static ALboolean IsValidType(ALenum type)
+static ALbuffer *AllocBuffer(ALCcontext *context)
{
- switch(type)
+ ALCdevice *device = context->Device;
+ BufferSubList *sublist, *subend;
+ ALbuffer *buffer = NULL;
+ ALsizei lidx = 0;
+ ALsizei slidx;
+
+ almtx_lock(&device->BufferLock);
+ sublist = VECTOR_BEGIN(device->BufferList);
+ subend = VECTOR_END(device->BufferList);
+ for(;sublist != subend;++sublist)
{
- case AL_BYTE_SOFT:
- case AL_UNSIGNED_BYTE_SOFT:
- case AL_SHORT_SOFT:
- case AL_UNSIGNED_SHORT_SOFT:
- case AL_INT_SOFT:
- case AL_UNSIGNED_INT_SOFT:
- case AL_FLOAT_SOFT:
- case AL_DOUBLE_SOFT:
- case AL_BYTE3_SOFT:
- case AL_UNSIGNED_BYTE3_SOFT:
- return AL_TRUE;
+ if(sublist->FreeMask)
+ {
+ slidx = CTZ64(sublist->FreeMask);
+ buffer = sublist->Buffers + slidx;
+ break;
+ }
+ ++lidx;
}
- return AL_FALSE;
-}
-
-static ALboolean IsValidChannels(ALenum channels)
-{
- switch(channels)
+ if(UNLIKELY(!buffer))
{
- case AL_MONO_SOFT:
- case AL_STEREO_SOFT:
- case AL_REAR_SOFT:
- case AL_QUAD_SOFT:
- case AL_5POINT1_SOFT:
- case AL_6POINT1_SOFT:
- case AL_7POINT1_SOFT:
- return AL_TRUE;
+ const BufferSubList empty_sublist = { 0, NULL };
+ /* Don't allocate so many list entries that the 32-bit ID could
+ * overflow...
+ */
+ if(UNLIKELY(VECTOR_SIZE(device->BufferList) >= 1<<25))
+ {
+ almtx_unlock(&device->BufferLock);
+ alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated");
+ return NULL;
+ }
+ lidx = (ALsizei)VECTOR_SIZE(device->BufferList);
+ VECTOR_PUSH_BACK(device->BufferList, empty_sublist);
+ sublist = &VECTOR_BACK(device->BufferList);
+ sublist->FreeMask = ~U64(0);
+ sublist->Buffers = al_calloc(16, sizeof(ALbuffer)*64);
+ if(UNLIKELY(!sublist->Buffers))
+ {
+ VECTOR_POP_BACK(device->BufferList);
+ almtx_unlock(&device->BufferLock);
+ alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch");
+ return NULL;
+ }
+
+ slidx = 0;
+ buffer = sublist->Buffers + slidx;
}
- return AL_FALSE;
-}
+ memset(buffer, 0, sizeof(*buffer));
-ALbuffer *NewBuffer(ALCcontext *context)
-{
- ALCdevice *device = context->Device;
- ALbuffer *buffer;
- ALenum err;
-
- buffer = calloc(1, sizeof(ALbuffer));
- if(!buffer)
- SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL);
- RWLockInit(&buffer->lock);
-
- err = NewThunkEntry(&buffer->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer);
- if(err != AL_NO_ERROR)
- {
- FreeThunkEntry(buffer->id);
- memset(buffer, 0, sizeof(ALbuffer));
- free(buffer);
+ /* Add 1 to avoid buffer ID 0. */
+ buffer->id = ((lidx<<6) | slidx) + 1;
- SET_ERROR_AND_RETURN_VALUE(context, err, NULL);
- }
+ sublist->FreeMask &= ~(U64(1)<<slidx);
+ almtx_unlock(&device->BufferLock);
return buffer;
}
-void DeleteBuffer(ALCdevice *device, ALbuffer *buffer)
+static void FreeBuffer(ALCdevice *device, ALbuffer *buffer)
{
- RemoveBuffer(device, buffer->id);
- FreeThunkEntry(buffer->id);
-
- free(buffer->data);
+ ALuint id = buffer->id - 1;
+ ALsizei lidx = id >> 6;
+ ALsizei slidx = id & 0x3f;
+ al_free(buffer->data);
memset(buffer, 0, sizeof(*buffer));
- free(buffer);
+
+ VECTOR_ELEM(device->BufferList, lidx).FreeMask |= U64(1) << slidx;
}
@@ -1344,16 +1281,25 @@ void DeleteBuffer(ALCdevice *device, ALbuffer *buffer)
*/
ALvoid ReleaseALBuffers(ALCdevice *device)
{
- ALsizei i;
- for(i = 0;i < device->BufferMap.size;i++)
+ BufferSubList *sublist = VECTOR_BEGIN(device->BufferList);
+ BufferSubList *subend = VECTOR_END(device->BufferList);
+ size_t leftover = 0;
+ for(;sublist != subend;++sublist)
{
- ALbuffer *temp = device->BufferMap.array[i].value;
- device->BufferMap.array[i].value = NULL;
+ ALuint64 usemask = ~sublist->FreeMask;
+ while(usemask)
+ {
+ ALsizei idx = CTZ64(usemask);
+ ALbuffer *buffer = sublist->Buffers + idx;
- free(temp->data);
+ al_free(buffer->data);
+ memset(buffer, 0, sizeof(*buffer));
+ ++leftover;
- FreeThunkEntry(temp->id);
- memset(temp, 0, sizeof(ALbuffer));
- free(temp);
+ usemask &= ~(U64(1) << idx);
+ }
+ sublist->FreeMask = ~usemask;
}
+ if(leftover > 0)
+ WARN("(%p) Deleted "SZFMT" Buffer%s\n", device, leftover, (leftover==1)?"":"s");
}
diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c
index 0bfe11b9..c2a78a0c 100644
--- a/OpenAL32/alEffect.c
+++ b/OpenAL32/alEffect.c
@@ -28,22 +28,53 @@
#include "AL/alc.h"
#include "alMain.h"
#include "alEffect.h"
-#include "alThunk.h"
#include "alError.h"
-ALboolean DisabledEffects[MAX_EFFECTS];
-
-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 },
+ { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH },
+ { "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 },
+ { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER },
+ { "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;
@@ -51,37 +82,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 = calloc(1, sizeof(ALeffect));
- ALenum err = AL_OUT_OF_MEMORY;
- if(!effect || (err=InitEffect(effect)) != AL_NO_ERROR)
- {
- free(effect);
- alDeleteEffects(cur, effects);
- SET_ERROR_AND_GOTO(context, err, done);
- }
-
- err = NewThunkEntry(&effect->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&device->EffectMap, effect->id, effect);
- if(err != AL_NO_ERROR)
+ ALeffect *effect = AllocEffect(context);
+ if(!effect)
{
- FreeThunkEntry(effect->id);
- memset(effect, 0, sizeof(ALeffect));
- free(effect);
-
alDeleteEffects(cur, effects);
- SET_ERROR_AND_GOTO(context, err, done);
+ break;
}
-
effects[cur] = effect->id;
}
-done:
ALCcontext_DecRef(context);
}
@@ -95,26 +107,23 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
context = GetContextRef();
if(!context) return;
- if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
device = context->Device;
+ LockEffectList(device);
+ if(!(n >= 0))
+ 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));
- free(effect);
+ if((effect=LookupEffect(device, effects[i])) != NULL)
+ FreeEffect(device, effect);
}
done:
+ UnlockEffectList(device);
ALCcontext_DecRef(context);
}
@@ -126,8 +135,10 @@ AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
Context = GetContextRef();
if(!Context) return AL_FALSE;
+ LockEffectList(Context->Device);
result = ((!effect || LookupEffect(Context->Device, effect)) ?
AL_TRUE : AL_FALSE);
+ UnlockEffectList(Context->Device);
ALCcontext_DecRef(Context);
@@ -144,15 +155,16 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
if(!Context) return;
Device = Context->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])
@@ -162,14 +174,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);
}
}
+ UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@@ -191,13 +204,15 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v
if(!Context) return;
Device = Context->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);
}
+ UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@@ -212,13 +227,15 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
if(!Context) return;
Device = Context->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);
}
+ UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@@ -233,13 +250,15 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat
if(!Context) return;
Device = Context->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);
}
+ UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@@ -254,8 +273,9 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value
if(!Context) return;
Device = Context->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)
@@ -263,9 +283,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);
}
}
+ UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@@ -287,13 +308,15 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu
if(!Context) return;
Device = Context->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);
}
+ UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@@ -308,13 +331,15 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val
if(!Context) return;
Device = Context->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);
}
+ UnlockEffectList(Device);
ALCcontext_DecRef(Context);
}
@@ -329,37 +354,120 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va
if(!Context) return;
Device = Context->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);
}
+ 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++)
+ ALCdevice *device = context->Device;
+ EffectSubList *sublist, *subend;
+ ALeffect *effect = NULL;
+ ALsizei lidx = 0;
+ ALsizei slidx;
+
+ 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)
{
- ALeffect *temp = device->EffectMap.array[i].value;
- device->EffectMap.array[i].value = NULL;
+ ALuint64 usemask = ~sublist->FreeMask;
+ while(usemask)
+ {
+ ALsizei idx = CTZ64(usemask);
+ ALeffect *effect = sublist->Effects + idx;
+
+ memset(effect, 0, sizeof(*effect));
+ ++leftover;
- // Release effect structure
- FreeThunkEntry(temp->id);
- memset(temp, 0, sizeof(ALeffect));
- free(temp);
+ usemask &= ~(U64(1) << idx);
+ }
+ sublist->FreeMask = ~usemask;
}
+ if(leftover > 0)
+ WARN("(%p) Deleted "SZFMT" Effect%s\n", device, leftover, (leftover==1)?"":"s");
}
@@ -395,7 +503,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;
@@ -425,14 +533,14 @@ 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_AUTOWAH:
effect->Props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME;
- effect->Props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
effect->Props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME;
effect->Props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE;
- SET_VTABLE1(ALautowah, effect);
+ effect->Props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
+ effect->vtab = &ALautowah_vtable;
break;
case AL_EFFECT_CHORUS:
effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM;
@@ -441,11 +549,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;
@@ -453,7 +561,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;
@@ -461,7 +569,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;
@@ -474,30 +582,41 @@ 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_FREQUENCY_SHIFTER:
+ effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
+ effect->Props.Fshifter.LeftDirection = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION;
+ effect->Props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION;
+ effect->vtab = &ALfshifter_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;
@@ -640,7 +759,7 @@ static const struct {
};
#undef DECL
-ALvoid LoadReverbPreset(const char *name, ALeffect *effect)
+void LoadReverbPreset(const char *name, ALeffect *effect)
{
size_t i;
@@ -651,9 +770,9 @@ ALvoid LoadReverbPreset(const char *name, ALeffect *effect)
return;
}
- if(!DisabledEffects[EAXREVERB])
+ if(!DisabledEffects[EAXREVERB_EFFECT])
InitEffectParams(effect, AL_EFFECT_EAXREVERB);
- else if(!DisabledEffects[REVERB])
+ else if(!DisabledEffects[REVERB_EFFECT])
InitEffectParams(effect, AL_EFFECT_REVERB);
else
InitEffectParams(effect, AL_EFFECT_NULL);
diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c
index b38d8dfe..b6208f77 100644
--- a/OpenAL32/alError.c
+++ b/OpenAL32/alError.c
@@ -21,6 +21,7 @@
#include "config.h"
#include <signal.h>
+#include <stdarg.h>
#ifdef HAVE_WINDOWS_H
#define WIN32_LEAN_AND_MEAN
@@ -33,9 +34,32 @@
ALboolean TrapALError = AL_FALSE;
-ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
+void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...)
{
ALenum curerr = AL_NO_ERROR;
+ char message[1024] = { 0 };
+ va_list args;
+ int msglen;
+
+ va_start(args, msg);
+ msglen = vsnprintf(message, sizeof(message), msg, args);
+ va_end(args);
+
+ if(msglen < 0 || (size_t)msglen >= sizeof(message))
+ {
+ message[sizeof(message)-1] = 0;
+ msglen = (int)strlen(message);
+ }
+ if(msglen > 0)
+ msg = message;
+ else
+ {
+ msg = "<internal error constructing message>";
+ msglen = (int)strlen(msg);
+ }
+
+ WARN("Error generated on context %p, code 0x%04x, \"%s\"\n",
+ context, errorCode, message);
if(TrapALError)
{
#ifdef _WIN32
@@ -46,17 +70,30 @@ ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
raise(SIGTRAP);
#endif
}
- ATOMIC_COMPARE_EXCHANGE_STRONG(ALenum, &Context->LastError, &curerr, errorCode);
+
+ ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&context->LastError, &curerr, errorCode);
+ if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Error))
+ {
+ ALbitfieldSOFT enabledevts;
+ almtx_lock(&context->EventCbLock);
+ enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed);
+ if((enabledevts&EventType_Error) && context->EventCb)
+ (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg,
+ context->EventParam);
+ almtx_unlock(&context->EventCbLock);
+ }
}
AL_API ALenum AL_APIENTRY alGetError(void)
{
- ALCcontext *Context;
+ ALCcontext *context;
ALenum errorCode;
- Context = GetContextRef();
- if(!Context)
+ context = GetContextRef();
+ if(!context)
{
+ const ALenum deferror = AL_INVALID_OPERATION;
+ WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror);
if(TrapALError)
{
#ifdef _WIN32
@@ -66,12 +103,11 @@ AL_API ALenum AL_APIENTRY alGetError(void)
raise(SIGTRAP);
#endif
}
- return AL_INVALID_OPERATION;
+ return deferror;
}
- errorCode = ATOMIC_EXCHANGE(ALenum, &Context->LastError, AL_NO_ERROR);
-
- ALCcontext_DecRef(Context);
+ errorCode = ATOMIC_EXCHANGE_SEQ(&context->LastError, AL_NO_ERROR);
+ ALCcontext_DecRef(context);
return errorCode;
}
diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c
index 609cc969..f6378c70 100644
--- a/OpenAL32/alExtension.c
+++ b/OpenAL32/alExtension.c
@@ -35,25 +35,6 @@
#include "AL/alc.h"
-const struct EffectList EffectList[] = {
- { "eaxreverb", EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB },
- { "reverb", REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB },
-#if 0
- { "autowah", AUTOWAH, "AL_EFFECT_AUTOWAH", AL_EFFECT_AUTOWAH },
-#endif
- { "chorus", CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS },
- { "compressor", COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR },
- { "distortion", DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION },
- { "echo", ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO },
- { "equalizer", EQUALIZER, "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER },
- { "flanger", FLANGER, "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER },
- { "modulator", MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR },
- { "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
- { "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE },
- { NULL, 0, NULL, (ALenum)0 }
-};
-
-
AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName)
{
ALboolean ret = AL_FALSE;
@@ -64,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;
diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c
index 3cf82c32..e57653e0 100644
--- a/OpenAL32/alFilter.c
+++ b/OpenAL32/alFilter.c
@@ -25,60 +25,56 @@
#include "alMain.h"
#include "alu.h"
#include "alFilter.h"
-#include "alThunk.h"
#include "alError.h"
-extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id);
-extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id);
-extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample);
-extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope);
-extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth);
+#define FILTER_MIN_GAIN 0.0f
+#define FILTER_MAX_GAIN 4.0f /* +12dB */
+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 = calloc(1, 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));
- free(filter);
-
- alDeleteFilters(cur, filters);
- SET_ERROR_AND_GOTO(context, err, done);
+ break;
}
filters[cur] = filter->id;
}
-done:
ALCcontext_DecRef(context);
}
@@ -92,26 +88,23 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
context = GetContextRef();
if(!context) return;
- if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
device = context->Device;
+ LockFilterList(device);
+ if(!(n >= 0))
+ 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));
- free(filter);
+ if((filter=LookupFilter(device, filters[i])) != NULL)
+ FreeFilter(device, filter);
}
done:
+ UnlockFilterList(device);
ALCcontext_DecRef(context);
}
@@ -123,8 +116,10 @@ AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
Context = GetContextRef();
if(!Context) return AL_FALSE;
+ LockFilterList(Context->Device);
result = ((!filter || LookupFilter(Context->Device, filter)) ?
AL_TRUE : AL_FALSE);
+ UnlockFilterList(Context->Device);
ALCcontext_DecRef(Context);
@@ -141,8 +136,9 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
if(!Context) return;
Device = Context->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)
@@ -151,14 +147,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);
}
}
+ UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@@ -180,13 +177,15 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v
if(!Context) return;
Device = Context->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);
}
+ UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@@ -201,13 +200,15 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
if(!Context) return;
Device = Context->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);
}
+ UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@@ -222,13 +223,15 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat
if(!Context) return;
Device = Context->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);
}
+ UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@@ -243,8 +246,9 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value
if(!Context) return;
Device = Context->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)
@@ -252,9 +256,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);
}
}
+ UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@@ -276,13 +281,15 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu
if(!Context) return;
Device = Context->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);
}
+ UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@@ -297,13 +304,15 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val
if(!Context) return;
Device = Context->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);
}
+ UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
@@ -318,159 +327,52 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va
if(!Context) return;
Device = Context->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);
}
+ UnlockFilterList(Device);
ALCcontext_DecRef(Context);
}
-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)
-{
- ALfloat alpha, sqrtgain_alpha_2;
- ALfloat w0, sin_w0, cos_w0;
-
- // Limit gain to -100dB
- gain = maxf(gain, 0.00001f);
-
- w0 = F_TAU * freq_mult;
- sin_w0 = sinf(w0);
- cos_w0 = cosf(w0);
- alpha = sin_w0/2.0f * rcpQ;
-
- /* Calculate filter coefficients depending on filter type */
- switch(type)
- {
- case ALfilterType_HighShelf:
- sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
- filter->b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
- filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 );
- filter->b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
- filter->a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
- filter->a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 );
- filter->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;
- filter->b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
- filter->b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 );
- filter->b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
- filter->a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
- filter->a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 );
- filter->a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
- break;
- case ALfilterType_Peaking:
- gain = sqrtf(gain);
- filter->b[0] = 1.0f + alpha * gain;
- filter->b[1] = -2.0f * cos_w0;
- filter->b[2] = 1.0f - alpha * gain;
- filter->a[0] = 1.0f + alpha / gain;
- filter->a[1] = -2.0f * cos_w0;
- filter->a[2] = 1.0f - alpha / gain;
- break;
-
- case ALfilterType_LowPass:
- filter->b[0] = (1.0f - cos_w0) / 2.0f;
- filter->b[1] = 1.0f - cos_w0;
- filter->b[2] = (1.0f - cos_w0) / 2.0f;
- filter->a[0] = 1.0f + alpha;
- filter->a[1] = -2.0f * cos_w0;
- filter->a[2] = 1.0f - alpha;
- break;
- case ALfilterType_HighPass:
- filter->b[0] = (1.0f + cos_w0) / 2.0f;
- filter->b[1] = -(1.0f + cos_w0);
- filter->b[2] = (1.0f + cos_w0) / 2.0f;
- filter->a[0] = 1.0f + alpha;
- filter->a[1] = -2.0f * cos_w0;
- filter->a[2] = 1.0f - alpha;
- break;
- case ALfilterType_BandPass:
- filter->b[0] = alpha;
- filter->b[1] = 0;
- filter->b[2] = -alpha;
- filter->a[0] = 1.0f + alpha;
- filter->a[1] = -2.0f * cos_w0;
- filter->a[2] = 1.0f - alpha;
- break;
- }
-
- filter->b[2] /= filter->a[0];
- filter->b[1] /= filter->a[0];
- filter->b[0] /= filter->a[0];
- filter->a[2] /= filter->a[0];
- filter->a[1] /= filter->a[0];
- filter->a[0] /= filter->a[0];
-
- filter->process = ALfilterState_processC;
-}
-
-void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples)
-{
- if(numsamples >= 2)
- {
- filter->x[1] = src[numsamples-2];
- filter->x[0] = src[numsamples-1];
- filter->y[1] = src[numsamples-2];
- filter->y[0] = src[numsamples-1];
- }
- else if(numsamples == 1)
- {
- filter->x[1] = filter->x[0];
- filter->x[0] = src[0];
- filter->y[1] = filter->y[0];
- filter->y[0] = src[0];
- }
-}
-
-
-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);
+ if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
+ 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 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_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
+{ ALlowpass_setParamf(filter, context, param, vals[0]); }
+
+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)
{
@@ -483,49 +385,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);
+ if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
+ 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 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_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
+{ ALhighpass_setParamf(filter, context, param, vals[0]); }
+
+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)
{
@@ -538,55 +438,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);
+ if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
+ 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 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_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
+{ ALbandpass_setParamf(filter, context, param, vals[0]); }
+
+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)
{
@@ -603,47 +501,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;
+
+ almtx_lock(&device->FilterLock);
+ sublist = VECTOR_BEGIN(device->FilterList);
+ subend = VECTOR_END(device->FilterList);
+ for(;sublist != subend;++sublist)
+ {
+ 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);
-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); }
+ /* Add 1 to avoid filter ID 0. */
+ filter->id = ((lidx<<6) | slidx) + 1;
-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); }
+ sublist->FreeMask &= ~(U64(1)<<slidx);
+ almtx_unlock(&device->FilterLock);
+ return filter;
+}
-ALvoid ReleaseALFilters(ALCdevice *device)
+static void FreeFilter(ALCdevice *device, ALfilter *filter)
{
- ALsizei i;
- for(i = 0;i < device->FilterMap.size;i++)
+ 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)
{
- ALfilter *temp = device->FilterMap.array[i].value;
- device->FilterMap.array[i].value = NULL;
+ ALuint64 usemask = ~sublist->FreeMask;
+ while(usemask)
+ {
+ ALsizei idx = CTZ64(usemask);
+ ALfilter *filter = sublist->Filters + idx;
+
+ memset(filter, 0, sizeof(*filter));
+ ++leftover;
- // Release filter structure
- FreeThunkEntry(temp->id);
- memset(temp, 0, sizeof(ALfilter));
- free(temp);
+ usemask &= ~(U64(1) << idx);
+ }
+ sublist->FreeMask = ~usemask;
}
+ if(leftover > 0)
+ WARN("(%p) Deleted "SZFMT" Filter%s\n", device, leftover, (leftover==1)?"":"s");
}
@@ -656,15 +638,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)
{
@@ -673,15 +647,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)
{
@@ -690,15 +656,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
{
@@ -707,15 +665,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;
}
diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c
index 66865473..f1ac3ff4 100644
--- a/OpenAL32/alListener.c
+++ b/OpenAL32/alListener.c
@@ -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;
+ 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;
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
+ 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;
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
+ 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");
}
done:
+ 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;
+ 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);
-
- LockContext(context);
- aluVectorSet(&context->Listener->Position, value1, value2, value3, 1.0f);
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
- UnlockContext(context);
+ 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);
-
- LockContext(context);
- aluVectorSet(&context->Listener->Velocity, value1, value2, value3, 0.0f);
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
- UnlockContext(context);
+ 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");
}
done:
+ 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;
- 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);
-
- LockContext(context);
+ 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];
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
- UnlockContext(context);
+ 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");
}
done:
+ almtx_unlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -158,13 +173,14 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
context = GetContextRef();
if(!context) return;
+ 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");
}
+ almtx_unlock(&context->PropLock);
-done:
ALCcontext_DecRef(context);
}
@@ -184,13 +200,14 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A
context = GetContextRef();
if(!context) return;
+ 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");
}
+ almtx_unlock(&context->PropLock);
-done:
ALCcontext_DecRef(context);
}
@@ -224,15 +241,16 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
context = GetContextRef();
if(!context) return;
- 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");
}
+ almtx_unlock(&context->PropLock);
-done:
ALCcontext_DecRef(context);
}
@@ -244,23 +262,24 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
context = GetContextRef();
if(!context) return;
- 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:
ALCcontext_DecRef(context);
}
@@ -272,31 +291,28 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat
context = GetContextRef();
if(!context) return;
- 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:
- LockContext(context);
- *value1 = context->Listener->Position.v[0];
- *value2 = context->Listener->Position.v[1];
- *value3 = context->Listener->Position.v[2];
- UnlockContext(context);
+ *value1 = context->Listener->Position[0];
+ *value2 = context->Listener->Position[1];
+ *value3 = context->Listener->Position[2];
break;
case AL_VELOCITY:
- LockContext(context);
- *value1 = context->Listener->Velocity.v[0];
- *value2 = context->Listener->Velocity.v[1];
- *value3 = context->Listener->Velocity.v[2];
- UnlockContext(context);
+ *value1 = context->Listener->Velocity[0];
+ *value2 = context->Listener->Velocity[1];
+ *value3 = context->Listener->Velocity[2];
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:
ALCcontext_DecRef(context);
}
@@ -321,12 +337,12 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
context = GetContextRef();
if(!context) return;
- 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:
- LockContext(context);
// AT then UP
values[0] = context->Listener->Forward[0];
values[1] = context->Listener->Forward[1];
@@ -334,14 +350,13 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
values[3] = context->Listener->Up[0];
values[4] = context->Listener->Up[1];
values[5] = context->Listener->Up[2];
- UnlockContext(context);
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:
ALCcontext_DecRef(context);
}
@@ -353,15 +368,16 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
context = GetContextRef();
if(!context) return;
- 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:
ALCcontext_DecRef(context);
}
@@ -373,31 +389,28 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
context = GetContextRef();
if(!context) return;
- 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:
- LockContext(context);
- *value1 = (ALint)context->Listener->Position.v[0];
- *value2 = (ALint)context->Listener->Position.v[1];
- *value3 = (ALint)context->Listener->Position.v[2];
- UnlockContext(context);
+ *value1 = (ALint)context->Listener->Position[0];
+ *value2 = (ALint)context->Listener->Position[1];
+ *value3 = (ALint)context->Listener->Position[2];
break;
case AL_VELOCITY:
- LockContext(context);
- *value1 = (ALint)context->Listener->Velocity.v[0];
- *value2 = (ALint)context->Listener->Velocity.v[1];
- *value3 = (ALint)context->Listener->Velocity.v[2];
- UnlockContext(context);
+ *value1 = (ALint)context->Listener->Velocity[0];
+ *value2 = (ALint)context->Listener->Velocity[1];
+ *value3 = (ALint)context->Listener->Velocity[2];
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:
ALCcontext_DecRef(context);
}
@@ -417,12 +430,12 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
context = GetContextRef();
if(!context) return;
- 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:
- LockContext(context);
// AT then UP
values[0] = (ALint)context->Listener->Forward[0];
values[1] = (ALint)context->Listener->Forward[1];
@@ -430,13 +443,60 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
values[3] = (ALint)context->Listener->Up[0];
values[4] = (ALint)context->Listener->Up[1];
values[5] = (ALint)context->Listener->Up[2];
- UnlockContext(context);
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:
ALCcontext_DecRef(context);
}
+
+
+void UpdateListenerProps(ALCcontext *context)
+{
+ ALlistener *listener = context->Listener;
+ struct ALlistenerProps *props;
+
+ /* Get an unused proprty container, or allocate a new one as needed. */
+ props = ATOMIC_LOAD(&context->FreeListenerProps, almemory_order_acquire);
+ if(!props)
+ props = al_calloc(16, sizeof(*props));
+ else
+ {
+ struct ALlistenerProps *next;
+ do {
+ next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
+ } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeListenerProps, &props, next,
+ almemory_order_seq_cst, almemory_order_acquire) == 0);
+ }
+
+ /* Copy in current property values. */
+ props->Position[0] = listener->Position[0];
+ props->Position[1] = listener->Position[1];
+ props->Position[2] = listener->Position[2];
+
+ props->Velocity[0] = listener->Velocity[0];
+ props->Velocity[1] = listener->Velocity[1];
+ props->Velocity[2] = listener->Velocity[2];
+
+ props->Forward[0] = listener->Forward[0];
+ props->Forward[1] = listener->Forward[1];
+ props->Forward[2] = listener->Forward[2];
+ props->Up[0] = listener->Up[0];
+ props->Up[1] = listener->Up[1];
+ props->Up[2] = listener->Up[2];
+
+ props->Gain = listener->Gain;
+
+ /* Set the new container for updating internal parameters. */
+ props = ATOMIC_EXCHANGE_PTR(&listener->Update, props, almemory_order_acq_rel);
+ if(props)
+ {
+ /* If there was an unused update container, put it back in the
+ * freelist.
+ */
+ ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &context->FreeListenerProps, props);
+ }
+}
diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c
index 0d454882..d7c68e4e 100644
--- a/OpenAL32/alSource.c
+++ b/OpenAL32/alSource.c
@@ -31,22 +31,82 @@
#include "alError.h"
#include "alSource.h"
#include "alBuffer.h"
-#include "alThunk.h"
+#include "alFilter.h"
#include "alAuxEffectSlot.h"
+#include "ringbuffer.h"
#include "backends/base.h"
#include "threads.h"
+#include "almalloc.h"
+
+
+static ALsource *AllocSource(ALCcontext *context);
+static void FreeSource(ALCcontext *context, ALsource *source);
+static void InitSourceParams(ALsource *Source, ALsizei num_sends);
+static void DeinitSource(ALsource *source, ALsizei num_sends);
+static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context);
+static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
+static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
+static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context);
+static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac);
+static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice);
+
+static inline void LockSourceList(ALCcontext *context)
+{ almtx_lock(&context->SourceLock); }
+static inline void UnlockSourceList(ALCcontext *context)
+{ almtx_unlock(&context->SourceLock); }
+
+static inline ALsource *LookupSource(ALCcontext *context, ALuint id)
+{
+ SourceSubList *sublist;
+ ALuint lidx = (id-1) >> 6;
+ ALsizei slidx = (id-1) & 0x3f;
+
+ if(UNLIKELY(lidx >= VECTOR_SIZE(context->SourceList)))
+ return NULL;
+ sublist = &VECTOR_ELEM(context->SourceList, lidx);
+ if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
+ return NULL;
+ return sublist->Sources + slidx;
+}
+
+static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
+{
+ BufferSubList *sublist;
+ ALuint lidx = (id-1) >> 6;
+ ALsizei slidx = (id-1) & 0x3f;
+
+ if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList)))
+ return NULL;
+ sublist = &VECTOR_ELEM(device->BufferList, lidx);
+ if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
+ return NULL;
+ return sublist->Buffers + slidx;
+}
+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;
+}
-extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
-extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
+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 ALvoid InitSourceParams(ALsource *Source);
-static ALint64 GetSourceSampleOffset(ALsource *Source);
-static ALdouble GetSourceSecOffset(ALsource *Source);
-static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
-static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
typedef enum SourceProp {
srcPitch = AL_PITCH,
@@ -92,20 +152,28 @@ typedef enum SourceProp {
/* AL_EXT_source_distance_model */
srcDistanceModel = AL_DISTANCE_MODEL,
- srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
- srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
- srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
-
- /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
- srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
- srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
-
/* AL_SOFT_source_latency */
srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
+ /* AL_EXT_STEREO_ANGLES */
+ srcAngles = AL_STEREO_ANGLES,
+
+ /* AL_EXT_SOURCE_RADIUS */
+ srcRadius = AL_SOURCE_RADIUS,
+
/* AL_EXT_BFORMAT */
srcOrientation = AL_ORIENTATION,
+
+ /* AL_SOFT_source_resampler */
+ srcResampler = AL_SOURCE_RESAMPLER_SOFT,
+
+ /* AL_SOFT_source_spatialize */
+ srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT,
+
+ /* ALC_SOFT_device_clock */
+ srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT,
+ srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT,
} SourceProp;
static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
@@ -116,6 +184,75 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p
static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
+static inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context)
+{
+ ALint idx = source->VoiceIdx;
+ if(idx >= 0 && idx < context->VoiceCount)
+ {
+ ALvoice *voice = context->Voices[idx];
+ if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == source)
+ return voice;
+ }
+ source->VoiceIdx = -1;
+ return NULL;
+}
+
+/**
+ * Returns if the last known state for the source was playing or paused. Does
+ * not sync with the mixer voice.
+ */
+static inline bool IsPlayingOrPaused(ALsource *source)
+{ return source->state == AL_PLAYING || source->state == AL_PAUSED; }
+
+/**
+ * Returns an updated source state using the matching voice's status (or lack
+ * thereof).
+ */
+static inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
+{
+ if(!voice && source->state == AL_PLAYING)
+ source->state = AL_STOPPED;
+ return source->state;
+}
+
+/**
+ * Returns if the source should specify an update, given the context's
+ * deferring state and the source's last known state.
+ */
+static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
+{
+ return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) &&
+ IsPlayingOrPaused(source);
+}
+
+
+/** Can only be called while the mixer is locked! */
+static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state)
+{
+ AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange);
+ ALbitfieldSOFT enabledevt;
+
+ enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire);
+ if(!(enabledevt&EventType_SourceStateChange)) return;
+
+ evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT;
+ evt.u.user.id = id;
+ evt.u.user.param = state;
+ snprintf(evt.u.user.msg, sizeof(evt.u.user.msg), "Source ID %u state changed to %s", id,
+ (state==AL_INITIAL) ? "AL_INITIAL" :
+ (state==AL_PLAYING) ? "AL_PLAYING" :
+ (state==AL_PAUSED) ? "AL_PAUSED" :
+ (state==AL_STOPPED) ? "AL_STOPPED" : "<unknown>"
+ );
+ /* The mixer may have queued a state change that's not yet been processed,
+ * and we don't want state change messages to occur out of order, so send
+ * it through the async queue to ensure proper ordering.
+ */
+ if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1)
+ alsem_post(&context->EventSem);
+}
+
+
static ALint FloatValsByProp(ALenum prop)
{
if(prop != (ALenum)((SourceProp)prop))
@@ -150,13 +287,12 @@ static ALint FloatValsByProp(ALenum prop)
case AL_BUFFERS_QUEUED:
case AL_BUFFERS_PROCESSED:
case AL_SOURCE_TYPE:
- case AL_BYTE_LENGTH_SOFT:
- case AL_SAMPLE_LENGTH_SOFT:
- case AL_SEC_LENGTH_SOFT:
+ case AL_SOURCE_RADIUS:
+ case AL_SOURCE_RESAMPLER_SOFT:
+ case AL_SOURCE_SPATIALIZE_SOFT:
return 1;
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- case AL_BYTE_RW_OFFSETS_SOFT:
+ case AL_STEREO_ANGLES:
return 2;
case AL_POSITION:
@@ -168,6 +304,7 @@ static ALint FloatValsByProp(ALenum prop)
return 6;
case AL_SEC_OFFSET_LATENCY_SOFT:
+ case AL_SEC_OFFSET_CLOCK_SOFT:
break; /* Double only */
case AL_BUFFER:
@@ -175,6 +312,7 @@ static ALint FloatValsByProp(ALenum prop)
case AL_AUXILIARY_SEND_FILTER:
break; /* i/i64 only */
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ case AL_SAMPLE_OFFSET_CLOCK_SOFT:
break; /* i64 only */
}
return 0;
@@ -213,14 +351,14 @@ static ALint DoubleValsByProp(ALenum prop)
case AL_BUFFERS_QUEUED:
case AL_BUFFERS_PROCESSED:
case AL_SOURCE_TYPE:
- case AL_BYTE_LENGTH_SOFT:
- case AL_SAMPLE_LENGTH_SOFT:
- case AL_SEC_LENGTH_SOFT:
+ case AL_SOURCE_RADIUS:
+ case AL_SOURCE_RESAMPLER_SOFT:
+ case AL_SOURCE_SPATIALIZE_SOFT:
return 1;
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- case AL_BYTE_RW_OFFSETS_SOFT:
case AL_SEC_OFFSET_LATENCY_SOFT:
+ case AL_SEC_OFFSET_CLOCK_SOFT:
+ case AL_STEREO_ANGLES:
return 2;
case AL_POSITION:
@@ -236,6 +374,7 @@ static ALint DoubleValsByProp(ALenum prop)
case AL_AUXILIARY_SEND_FILTER:
break; /* i/i64 only */
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ case AL_SAMPLE_OFFSET_CLOCK_SOFT:
break; /* i64 only */
}
return 0;
@@ -277,15 +416,11 @@ static ALint IntValsByProp(ALenum prop)
case AL_BUFFERS_PROCESSED:
case AL_SOURCE_TYPE:
case AL_DIRECT_FILTER:
- case AL_BYTE_LENGTH_SOFT:
- case AL_SAMPLE_LENGTH_SOFT:
- case AL_SEC_LENGTH_SOFT:
+ case AL_SOURCE_RADIUS:
+ case AL_SOURCE_RESAMPLER_SOFT:
+ case AL_SOURCE_SPATIALIZE_SOFT:
return 1;
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- case AL_BYTE_RW_OFFSETS_SOFT:
- return 2;
-
case AL_POSITION:
case AL_VELOCITY:
case AL_DIRECTION:
@@ -296,9 +431,13 @@ static ALint IntValsByProp(ALenum prop)
return 6;
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ case AL_SAMPLE_OFFSET_CLOCK_SOFT:
break; /* i64 only */
case AL_SEC_OFFSET_LATENCY_SOFT:
+ case AL_SEC_OFFSET_CLOCK_SOFT:
break; /* Double only */
+ case AL_STEREO_ANGLES:
+ break; /* Float/double only */
}
return 0;
}
@@ -338,14 +477,13 @@ static ALint Int64ValsByProp(ALenum prop)
case AL_BUFFERS_PROCESSED:
case AL_SOURCE_TYPE:
case AL_DIRECT_FILTER:
- case AL_BYTE_LENGTH_SOFT:
- case AL_SAMPLE_LENGTH_SOFT:
- case AL_SEC_LENGTH_SOFT:
+ case AL_SOURCE_RADIUS:
+ case AL_SOURCE_RESAMPLER_SOFT:
+ case AL_SOURCE_SPATIALIZE_SOFT:
return 1;
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- case AL_BYTE_RW_OFFSETS_SOFT:
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ case AL_SAMPLE_OFFSET_CLOCK_SOFT:
return 2;
case AL_POSITION:
@@ -358,7 +496,10 @@ static ALint Int64ValsByProp(ALenum prop)
return 6;
case AL_SEC_OFFSET_LATENCY_SOFT:
+ case AL_SEC_OFFSET_CLOCK_SOFT:
break; /* Double only */
+ case AL_STEREO_ANGLES:
+ break; /* Float/double only */
}
return 0;
}
@@ -366,120 +507,130 @@ static ALint Int64ValsByProp(ALenum prop)
#define CHECKVAL(x) do { \
if(!(x)) \
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
+ { \
+ alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \
+ return AL_FALSE; \
+ } \
+} while(0)
+
+#define DO_UPDATEPROPS() do { \
+ ALvoice *voice; \
+ if(SourceShouldUpdate(Source, Context) && \
+ (voice=GetSourceVoice(Source, Context)) != NULL) \
+ UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \
+ else \
+ ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
} while(0)
static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
{
+ ALCdevice *device = Context->Device;
ALint ival;
switch(prop)
{
- case AL_BYTE_RW_OFFSETS_SOFT:
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- case AL_BYTE_LENGTH_SOFT:
- case AL_SAMPLE_LENGTH_SOFT:
- case AL_SEC_LENGTH_SOFT:
case AL_SEC_OFFSET_LATENCY_SOFT:
+ case AL_SEC_OFFSET_CLOCK_SOFT:
/* Query only */
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
+ SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
+ "Setting read-only source property 0x%04x", prop);
case AL_PITCH:
CHECKVAL(*values >= 0.0f);
Source->Pitch = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_CONE_INNER_ANGLE:
CHECKVAL(*values >= 0.0f && *values <= 360.0f);
Source->InnerAngle = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_CONE_OUTER_ANGLE:
CHECKVAL(*values >= 0.0f && *values <= 360.0f);
Source->OuterAngle = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_GAIN:
CHECKVAL(*values >= 0.0f);
Source->Gain = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_MAX_DISTANCE:
CHECKVAL(*values >= 0.0f);
Source->MaxDistance = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_ROLLOFF_FACTOR:
CHECKVAL(*values >= 0.0f);
- Source->RollOffFactor = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ Source->RolloffFactor = *values;
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_REFERENCE_DISTANCE:
CHECKVAL(*values >= 0.0f);
Source->RefDistance = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_MIN_GAIN:
- CHECKVAL(*values >= 0.0f && *values <= 1.0f);
+ CHECKVAL(*values >= 0.0f);
Source->MinGain = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_MAX_GAIN:
- CHECKVAL(*values >= 0.0f && *values <= 1.0f);
+ CHECKVAL(*values >= 0.0f);
Source->MaxGain = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_CONE_OUTER_GAIN:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->OuterGain = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_CONE_OUTER_GAINHF:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->OuterGainHF = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_AIR_ABSORPTION_FACTOR:
CHECKVAL(*values >= 0.0f && *values <= 10.0f);
Source->AirAbsorptionFactor = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_ROOM_ROLLOFF_FACTOR:
CHECKVAL(*values >= 0.0f && *values <= 10.0f);
Source->RoomRolloffFactor = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_DOPPLER_FACTOR:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->DopplerFactor = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_SEC_OFFSET:
@@ -487,66 +638,84 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_BYTE_OFFSET:
CHECKVAL(*values >= 0.0f);
- LockContext(Context);
Source->OffsetType = prop;
Source->Offset = *values;
- if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
- !Context->DeferUpdates)
+ if(IsPlayingOrPaused(Source))
{
- WriteLock(&Source->queue_lock);
- if(ApplyOffset(Source) == AL_FALSE)
+ ALvoice *voice;
+
+ ALCdevice_Lock(Context->Device);
+ /* Double-check that the source is still playing while we have
+ * the lock.
+ */
+ voice = GetSourceVoice(Source, Context);
+ if(voice)
{
- WriteUnlock(&Source->queue_lock);
- UnlockContext(Context);
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
+ if(ApplyOffset(Source, voice) == AL_FALSE)
+ {
+ ALCdevice_Unlock(Context->Device);
+ SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset");
+ }
}
- WriteUnlock(&Source->queue_lock);
+ ALCdevice_Unlock(Context->Device);
}
- UnlockContext(Context);
+ return AL_TRUE;
+
+ case AL_SOURCE_RADIUS:
+ CHECKVAL(*values >= 0.0f && isfinite(*values));
+
+ Source->Radius = *values;
+ DO_UPDATEPROPS();
+ return AL_TRUE;
+
+ case AL_STEREO_ANGLES:
+ CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
+
+ Source->StereoPan[0] = values[0];
+ Source->StereoPan[1] = values[1];
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_POSITION:
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
- LockContext(Context);
- aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
- UnlockContext(Context);
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ Source->Position[0] = values[0];
+ Source->Position[1] = values[1];
+ Source->Position[2] = values[2];
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_VELOCITY:
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
- LockContext(Context);
- aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
- UnlockContext(Context);
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ Source->Velocity[0] = values[0];
+ Source->Velocity[1] = values[1];
+ Source->Velocity[2] = values[2];
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_DIRECTION:
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
- LockContext(Context);
- aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
- UnlockContext(Context);
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ Source->Direction[0] = values[0];
+ Source->Direction[1] = values[1];
+ Source->Direction[2] = values[2];
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_ORIENTATION:
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
- LockContext(Context);
Source->Orientation[0][0] = values[0];
Source->Orientation[0][1] = values[1];
Source->Orientation[0][2] = values[2];
Source->Orientation[1][0] = values[3];
Source->Orientation[1][1] = values[4];
Source->Orientation[1][2] = values[5];
- UnlockContext(Context);
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
@@ -559,6 +728,8 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DIRECT_CHANNELS_SOFT:
+ case AL_SOURCE_RESAMPLER_SOFT:
+ case AL_SOURCE_SPATIALIZE_SOFT:
ival = (ALint)values[0];
return SetSourceiv(Source, Context, prop, &ival);
@@ -571,11 +742,12 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_DIRECT_FILTER:
case AL_AUXILIARY_SEND_FILTER:
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ case AL_SAMPLE_OFFSET_CLOCK_SOFT:
break;
}
ERR("Unexpected property: 0x%04x\n", prop);
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
+ SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop);
}
static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
@@ -585,7 +757,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
ALfilter *filter = NULL;
ALeffectslot *slot = NULL;
ALbufferlistitem *oldlist;
- ALbufferlistitem *newlist;
ALfloat fvals[6];
switch(prop)
@@ -594,73 +765,105 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_SOURCE_TYPE:
case AL_BUFFERS_QUEUED:
case AL_BUFFERS_PROCESSED:
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- case AL_BYTE_RW_OFFSETS_SOFT:
- case AL_BYTE_LENGTH_SOFT:
- case AL_SAMPLE_LENGTH_SOFT:
- case AL_SEC_LENGTH_SOFT:
/* Query only */
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
+ SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
+ "Setting read-only source property 0x%04x", prop);
case AL_SOURCE_RELATIVE:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->HeadRelative = (ALboolean)*values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_LOOPING:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->Looping = (ALboolean)*values;
+ if(IsPlayingOrPaused(Source))
+ {
+ ALvoice *voice = GetSourceVoice(Source, Context);
+ if(voice)
+ {
+ if(Source->Looping)
+ ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release);
+ else
+ ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_release);
+
+ /* If the source is playing, wait for the current mix to finish
+ * to ensure it isn't currently looping back or reaching the
+ * end.
+ */
+ while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
+ althrd_yield();
+ }
+ }
return AL_TRUE;
case AL_BUFFER:
- CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
+ LockBufferList(device);
+ if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
+ {
+ UnlockBufferList(device);
+ SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u",
+ *values);
+ }
- WriteLock(&Source->queue_lock);
- if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
+ if(buffer && buffer->MappedAccess != 0 &&
+ !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
{
- WriteUnlock(&Source->queue_lock);
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
+ UnlockBufferList(device);
+ SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
+ "Setting non-persistently mapped buffer %u", buffer->id);
+ }
+ else
+ {
+ ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
+ if(state == AL_PLAYING || state == AL_PAUSED)
+ {
+ UnlockBufferList(device);
+ SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
+ "Setting buffer on playing or paused source %u", Source->id);
+ }
}
+ oldlist = Source->queue;
if(buffer != NULL)
{
/* Add the selected buffer to a one-item queue */
- newlist = malloc(sizeof(ALbufferlistitem));
- newlist->buffer = buffer;
- newlist->next = NULL;
- newlist->prev = NULL;
+ ALbufferlistitem *newlist = al_calloc(DEF_ALIGN,
+ FAM_SIZE(ALbufferlistitem, buffers, 1));
+ ATOMIC_INIT(&newlist->next, NULL);
+ newlist->max_samples = buffer->SampleLen;
+ newlist->num_buffers = 1;
+ newlist->buffers[0] = buffer;
IncrementRef(&buffer->ref);
/* Source is now Static */
Source->SourceType = AL_STATIC;
-
- ReadLock(&buffer->lock);
- Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
- Source->SampleSize = BytesFromFmt(buffer->FmtType);
- ReadUnlock(&buffer->lock);
+ Source->queue = newlist;
}
else
{
/* Source is now Undetermined */
Source->SourceType = AL_UNDETERMINED;
- newlist = NULL;
+ Source->queue = NULL;
}
- oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
- ATOMIC_STORE(&Source->current_buffer, newlist);
- WriteUnlock(&Source->queue_lock);
+ UnlockBufferList(device);
/* Delete all elements in the previous queue */
while(oldlist != NULL)
{
+ ALsizei i;
ALbufferlistitem *temp = oldlist;
- oldlist = temp->next;
+ oldlist = ATOMIC_LOAD(&temp->next, almemory_order_relaxed);
- if(temp->buffer)
- DecrementRef(&temp->buffer->ref);
- free(temp);
+ for(i = 0;i < temp->num_buffers;i++)
+ {
+ if(temp->buffers[i])
+ DecrementRef(&temp->buffers[i]->ref);
+ }
+ al_free(temp);
}
return AL_TRUE;
@@ -669,29 +872,37 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_BYTE_OFFSET:
CHECKVAL(*values >= 0);
- LockContext(Context);
Source->OffsetType = prop;
Source->Offset = *values;
- if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
- !Context->DeferUpdates)
+ if(IsPlayingOrPaused(Source))
{
- WriteLock(&Source->queue_lock);
- if(ApplyOffset(Source) == AL_FALSE)
+ ALvoice *voice;
+
+ ALCdevice_Lock(Context->Device);
+ voice = GetSourceVoice(Source, Context);
+ if(voice)
{
- WriteUnlock(&Source->queue_lock);
- UnlockContext(Context);
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
+ if(ApplyOffset(Source, voice) == AL_FALSE)
+ {
+ ALCdevice_Unlock(Context->Device);
+ SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE,
+ "Invalid source offset");
+ }
}
- WriteUnlock(&Source->queue_lock);
+ ALCdevice_Unlock(Context->Device);
}
- UnlockContext(Context);
return AL_TRUE;
case AL_DIRECT_FILTER:
- CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
+ LockFilterList(device);
+ if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
+ {
+ UnlockFilterList(device);
+ SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u",
+ *values);
+ }
- LockContext(Context);
if(!filter)
{
Source->Direct.Gain = 1.0f;
@@ -708,36 +919,36 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
Source->Direct.GainLF = filter->GainLF;
Source->Direct.LFReference = filter->LFReference;
}
- UnlockContext(Context);
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ UnlockFilterList(device);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_DIRECT_FILTER_GAINHF_AUTO:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->DryGainHFAuto = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->WetGainAuto = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->WetGainHFAuto = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_DIRECT_CHANNELS_SOFT:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->DirectChannels = *values;
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_DISTANCE_MODEL:
@@ -751,24 +962,45 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
Source->DistanceModel = *values;
if(Context->SourceDistanceModel)
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ DO_UPDATEPROPS();
+ return AL_TRUE;
+
+ case AL_SOURCE_RESAMPLER_SOFT:
+ CHECKVAL(*values >= 0 && *values <= ResamplerMax);
+
+ Source->Resampler = *values;
+ DO_UPDATEPROPS();
+ return AL_TRUE;
+
+ case AL_SOURCE_SPATIALIZE_SOFT:
+ CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT);
+
+ Source->Spatialize = *values;
+ DO_UPDATEPROPS();
return AL_TRUE;
case AL_AUXILIARY_SEND_FILTER:
- LockContext(Context);
- if(!((ALuint)values[1] < device->NumAuxSends &&
- (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
- (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
+ LockEffectSlotList(Context);
+ if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL))
{
- UnlockContext(Context);
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
+ UnlockEffectSlotList(Context);
+ SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u",
+ values[0]);
+ }
+ if(!((ALuint)values[1] < (ALuint)device->NumAuxSends))
+ {
+ UnlockEffectSlotList(Context);
+ SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]);
+ }
+ LockFilterList(device);
+ if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL))
+ {
+ UnlockFilterList(device);
+ UnlockEffectSlotList(Context);
+ SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u",
+ values[2]);
}
-
- /* Add refcount on the new slot, and release the previous slot */
- if(slot) IncrementRef(&slot->ref);
- slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
- if(slot) DecrementRef(&slot->ref);
if(!filter)
{
@@ -787,8 +1019,35 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
Source->Send[values[1]].GainLF = filter->GainLF;
Source->Send[values[1]].LFReference = filter->LFReference;
}
- UnlockContext(Context);
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ UnlockFilterList(device);
+
+ if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
+ {
+ ALvoice *voice;
+ /* Add refcount on the new slot, and release the previous slot */
+ if(slot) IncrementRef(&slot->ref);
+ if(Source->Send[values[1]].Slot)
+ DecrementRef(&Source->Send[values[1]].Slot->ref);
+ Source->Send[values[1]].Slot = slot;
+
+ /* We must force an update if the auxiliary slot changed on an
+ * active source, in case the slot is about to be deleted.
+ */
+ if((voice=GetSourceVoice(Source, Context)) != NULL)
+ UpdateSourceProps(Source, voice, device->NumAuxSends, Context);
+ else
+ ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release);
+ }
+ else
+ {
+ if(slot) IncrementRef(&slot->ref);
+ if(Source->Send[values[1]].Slot)
+ DecrementRef(&Source->Send[values[1]].Slot->ref);
+ Source->Send[values[1]].Slot = slot;
+ DO_UPDATEPROPS();
+ }
+ UnlockEffectSlotList(Context);
+
return AL_TRUE;
@@ -807,6 +1066,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_CONE_OUTER_GAINHF:
case AL_AIR_ABSORPTION_FACTOR:
case AL_ROOM_ROLLOFF_FACTOR:
+ case AL_SOURCE_RADIUS:
fvals[0] = (ALfloat)*values;
return SetSourcefv(Source, Context, (int)prop, fvals);
@@ -831,11 +1091,15 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
case AL_SEC_OFFSET_LATENCY_SOFT:
+ case AL_SEC_OFFSET_CLOCK_SOFT:
+ case AL_SAMPLE_OFFSET_CLOCK_SOFT:
+ case AL_STEREO_ANGLES:
break;
}
ERR("Unexpected property: 0x%04x\n", prop);
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
+ SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x",
+ prop);
}
static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
@@ -849,15 +1113,11 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp
case AL_BUFFERS_QUEUED:
case AL_BUFFERS_PROCESSED:
case AL_SOURCE_STATE:
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- case AL_BYTE_RW_OFFSETS_SOFT:
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
- case AL_BYTE_LENGTH_SOFT:
- case AL_SAMPLE_LENGTH_SOFT:
- case AL_SEC_LENGTH_SOFT:
+ case AL_SAMPLE_OFFSET_CLOCK_SOFT:
/* Query only */
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
-
+ SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
+ "Setting read-only source property 0x%04x", prop);
/* 1x int */
case AL_SOURCE_RELATIVE:
@@ -870,6 +1130,8 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DIRECT_CHANNELS_SOFT:
case AL_DISTANCE_MODEL:
+ case AL_SOURCE_RESAMPLER_SOFT:
+ case AL_SOURCE_SPATIALIZE_SOFT:
CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
ivals[0] = (ALint)*values;
@@ -909,6 +1171,7 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp
case AL_CONE_OUTER_GAINHF:
case AL_AIR_ABSORPTION_FACTOR:
case AL_ROOM_ROLLOFF_FACTOR:
+ case AL_SOURCE_RADIUS:
fvals[0] = (ALfloat)*values;
return SetSourcefv(Source, Context, (int)prop, fvals);
@@ -932,11 +1195,14 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp
return SetSourcefv(Source, Context, (int)prop, fvals);
case AL_SEC_OFFSET_LATENCY_SOFT:
+ case AL_SEC_OFFSET_CLOCK_SOFT:
+ case AL_STEREO_ANGLES:
break;
}
ERR("Unexpected property: 0x%04x\n", prop);
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
+ SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x",
+ prop);
}
#undef CHECKVAL
@@ -945,9 +1211,8 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp
static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
{
ALCdevice *device = Context->Device;
- ALbufferlistitem *BufferList;
- ALdouble offsets[2];
- ALdouble updateLen;
+ ClockLatency clocktime;
+ ALuint64 srcclock;
ALint ivals[3];
ALboolean err;
@@ -966,7 +1231,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p
return AL_TRUE;
case AL_ROLLOFF_FACTOR:
- *values = Source->RollOffFactor;
+ *values = Source->RolloffFactor;
return AL_TRUE;
case AL_REFERENCE_DISTANCE:
@@ -996,10 +1261,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
- LockContext(Context);
- GetSourceOffsets(Source, prop, offsets, 0.0);
- UnlockContext(Context);
- *values = offsets[0];
+ *values = GetSourceOffset(Source, prop, Context);
return AL_TRUE;
case AL_CONE_OUTER_GAINHF:
@@ -1018,76 +1280,67 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p
*values = Source->DopplerFactor;
return AL_TRUE;
- case AL_SEC_LENGTH_SOFT:
- ReadLock(&Source->queue_lock);
- if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
- *values = 0;
- else
- {
- ALint length = 0;
- ALsizei freq = 1;
- do {
- ALbuffer *buffer = BufferList->buffer;
- if(buffer && buffer->SampleLen > 0)
- {
- freq = buffer->Frequency;
- length += buffer->SampleLen;
- }
- } while((BufferList=BufferList->next) != NULL);
- *values = (ALdouble)length / (ALdouble)freq;
- }
- ReadUnlock(&Source->queue_lock);
+ case AL_SOURCE_RADIUS:
+ *values = Source->Radius;
return AL_TRUE;
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- case AL_BYTE_RW_OFFSETS_SOFT:
- LockContext(Context);
- updateLen = (ALdouble)device->UpdateSize / device->Frequency;
- GetSourceOffsets(Source, prop, values, updateLen);
- UnlockContext(Context);
+ case AL_STEREO_ANGLES:
+ values[0] = Source->StereoPan[0];
+ values[1] = Source->StereoPan[1];
return AL_TRUE;
case AL_SEC_OFFSET_LATENCY_SOFT:
- LockContext(Context);
- values[0] = GetSourceSecOffset(Source);
- values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
- 1000000000.0;
- UnlockContext(Context);
+ /* Get the source offset with the clock time first. Then get the
+ * clock time with the device latency. Order is important.
+ */
+ values[0] = GetSourceSecOffset(Source, Context, &srcclock);
+ almtx_lock(&device->BackendLock);
+ clocktime = GetClockLatency(device);
+ almtx_unlock(&device->BackendLock);
+ if(srcclock == (ALuint64)clocktime.ClockTime)
+ values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
+ else
+ {
+ /* If the clock time incremented, reduce the latency by that
+ * much since it's that much closer to the source offset it got
+ * earlier.
+ */
+ ALuint64 diff = clocktime.ClockTime - srcclock;
+ values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
+ 1000000000.0;
+ }
+ return AL_TRUE;
+
+ case AL_SEC_OFFSET_CLOCK_SOFT:
+ values[0] = GetSourceSecOffset(Source, Context, &srcclock);
+ values[1] = srcclock / 1000000000.0;
return AL_TRUE;
case AL_POSITION:
- LockContext(Context);
- values[0] = Source->Position.v[0];
- values[1] = Source->Position.v[1];
- values[2] = Source->Position.v[2];
- UnlockContext(Context);
+ values[0] = Source->Position[0];
+ values[1] = Source->Position[1];
+ values[2] = Source->Position[2];
return AL_TRUE;
case AL_VELOCITY:
- LockContext(Context);
- values[0] = Source->Velocity.v[0];
- values[1] = Source->Velocity.v[1];
- values[2] = Source->Velocity.v[2];
- UnlockContext(Context);
+ values[0] = Source->Velocity[0];
+ values[1] = Source->Velocity[1];
+ values[2] = Source->Velocity[2];
return AL_TRUE;
case AL_DIRECTION:
- LockContext(Context);
- values[0] = Source->Direction.v[0];
- values[1] = Source->Direction.v[1];
- values[2] = Source->Direction.v[2];
- UnlockContext(Context);
+ values[0] = Source->Direction[0];
+ values[1] = Source->Direction[1];
+ values[2] = Source->Direction[2];
return AL_TRUE;
case AL_ORIENTATION:
- LockContext(Context);
values[0] = Source->Orientation[0][0];
values[1] = Source->Orientation[0][1];
values[2] = Source->Orientation[0][2];
values[3] = Source->Orientation[1][0];
values[4] = Source->Orientation[1][1];
values[5] = Source->Orientation[1][2];
- UnlockContext(Context);
return AL_TRUE;
/* 1x int */
@@ -1101,9 +1354,9 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DIRECT_CHANNELS_SOFT:
- case AL_BYTE_LENGTH_SOFT:
- case AL_SAMPLE_LENGTH_SOFT:
case AL_DISTANCE_MODEL:
+ case AL_SOURCE_RESAMPLER_SOFT:
+ case AL_SOURCE_SPATIALIZE_SOFT:
if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
*values = (ALdouble)ivals[0];
return err;
@@ -1112,11 +1365,13 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_DIRECT_FILTER:
case AL_AUXILIARY_SEND_FILTER:
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ case AL_SAMPLE_OFFSET_CLOCK_SOFT:
break;
}
ERR("Unexpected property: 0x%04x\n", prop);
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
+ SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x",
+ prop);
}
static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
@@ -1136,89 +1391,30 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
return AL_TRUE;
case AL_BUFFER:
- ReadLock(&Source->queue_lock);
- BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
- ATOMIC_LOAD(&Source->current_buffer);
- *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
- ReadUnlock(&Source->queue_lock);
+ BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL;
+ *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ?
+ BufferList->buffers[0]->id : 0;
return AL_TRUE;
case AL_SOURCE_STATE:
- *values = Source->state;
- return AL_TRUE;
-
- case AL_BYTE_LENGTH_SOFT:
- ReadLock(&Source->queue_lock);
- if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
- *values = 0;
- else
- {
- ALint length = 0;
- do {
- ALbuffer *buffer = BufferList->buffer;
- if(buffer && buffer->SampleLen > 0)
- {
- ALuint byte_align, sample_align;
- if(buffer->OriginalType == UserFmtIMA4)
- {
- ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
- byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
- sample_align = buffer->OriginalAlign;
- }
- else if(buffer->OriginalType == UserFmtMSADPCM)
- {
- ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
- byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
- sample_align = buffer->OriginalAlign;
- }
- else
- {
- ALsizei align = buffer->OriginalAlign;
- byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
- sample_align = buffer->OriginalAlign;
- }
-
- length += buffer->SampleLen / sample_align * byte_align;
- }
- } while((BufferList=BufferList->next) != NULL);
- *values = length;
- }
- ReadUnlock(&Source->queue_lock);
- return AL_TRUE;
-
- case AL_SAMPLE_LENGTH_SOFT:
- ReadLock(&Source->queue_lock);
- if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
- *values = 0;
- else
- {
- ALint length = 0;
- do {
- ALbuffer *buffer = BufferList->buffer;
- if(buffer) length += buffer->SampleLen;
- } while((BufferList=BufferList->next) != NULL);
- *values = length;
- }
- ReadUnlock(&Source->queue_lock);
+ *values = GetSourceState(Source, GetSourceVoice(Source, Context));
return AL_TRUE;
case AL_BUFFERS_QUEUED:
- ReadLock(&Source->queue_lock);
- if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
+ if(!(BufferList=Source->queue))
*values = 0;
else
{
ALsizei count = 0;
do {
- ++count;
- } while((BufferList=BufferList->next) != NULL);
+ count += BufferList->num_buffers;
+ BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
+ } while(BufferList != NULL);
*values = count;
}
- ReadUnlock(&Source->queue_lock);
return AL_TRUE;
case AL_BUFFERS_PROCESSED:
- ReadLock(&Source->queue_lock);
if(Source->Looping || Source->SourceType != AL_STREAMING)
{
/* Buffers on a looping source are in a perpetual state of
@@ -1227,17 +1423,24 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
}
else
{
- const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
- const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
+ const ALbufferlistitem *BufferList = Source->queue;
+ const ALbufferlistitem *Current = NULL;
ALsizei played = 0;
+ ALvoice *voice;
+
+ if((voice=GetSourceVoice(Source, Context)) != NULL)
+ Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
+ else if(Source->state == AL_INITIAL)
+ Current = BufferList;
+
while(BufferList && BufferList != Current)
{
- played++;
- BufferList = BufferList->next;
+ played += BufferList->num_buffers;
+ BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
+ almemory_order_relaxed);
}
*values = played;
}
- ReadUnlock(&Source->queue_lock);
return AL_TRUE;
case AL_SOURCE_TYPE:
@@ -1264,6 +1467,14 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
*values = Source->DistanceModel;
return AL_TRUE;
+ case AL_SOURCE_RESAMPLER_SOFT:
+ *values = Source->Resampler;
+ return AL_TRUE;
+
+ case AL_SOURCE_SPATIALIZE_SOFT:
+ *values = Source->Spatialize;
+ return AL_TRUE;
+
/* 1x float/double */
case AL_CONE_INNER_ANGLE:
case AL_CONE_OUTER_ANGLE:
@@ -1282,21 +1493,11 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
case AL_AIR_ABSORPTION_FACTOR:
case AL_ROOM_ROLLOFF_FACTOR:
case AL_CONE_OUTER_GAINHF:
- case AL_SEC_LENGTH_SOFT:
+ case AL_SOURCE_RADIUS:
if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
*values = (ALint)dvals[0];
return err;
- /* 2x float/double */
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- case AL_BYTE_RW_OFFSETS_SOFT:
- if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
- {
- values[0] = (ALint)dvals[0];
- values[1] = (ALint)dvals[1];
- }
- return err;
-
/* 3x float/double */
case AL_POSITION:
case AL_VELOCITY:
@@ -1323,9 +1524,13 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
return err;
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ case AL_SAMPLE_OFFSET_CLOCK_SOFT:
break; /* i64 only */
case AL_SEC_OFFSET_LATENCY_SOFT:
+ case AL_SEC_OFFSET_CLOCK_SOFT:
break; /* Double only */
+ case AL_STEREO_ANGLES:
+ break; /* Float/double only */
case AL_DIRECT_FILTER:
case AL_AUXILIARY_SEND_FILTER:
@@ -1333,12 +1538,15 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p
}
ERR("Unexpected property: 0x%04x\n", prop);
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
+ SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x",
+ prop);
}
static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
{
ALCdevice *device = Context->Device;
+ ClockLatency clocktime;
+ ALuint64 srcclock;
ALdouble dvals[6];
ALint ivals[3];
ALboolean err;
@@ -1346,10 +1554,29 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp
switch(prop)
{
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
- LockContext(Context);
- values[0] = GetSourceSampleOffset(Source);
- values[1] = V0(device->Backend,getLatency)();
- UnlockContext(Context);
+ /* Get the source offset with the clock time first. Then get the
+ * clock time with the device latency. Order is important.
+ */
+ values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
+ almtx_lock(&device->BackendLock);
+ clocktime = GetClockLatency(device);
+ almtx_unlock(&device->BackendLock);
+ if(srcclock == (ALuint64)clocktime.ClockTime)
+ values[1] = clocktime.Latency;
+ else
+ {
+ /* If the clock time incremented, reduce the latency by that
+ * much since it's that much closer to the source offset it got
+ * earlier.
+ */
+ ALuint64 diff = clocktime.ClockTime - srcclock;
+ values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
+ }
+ return AL_TRUE;
+
+ case AL_SAMPLE_OFFSET_CLOCK_SOFT:
+ values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
+ values[1] = srcclock;
return AL_TRUE;
/* 1x float/double */
@@ -1370,21 +1597,11 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp
case AL_AIR_ABSORPTION_FACTOR:
case AL_ROOM_ROLLOFF_FACTOR:
case AL_CONE_OUTER_GAINHF:
- case AL_SEC_LENGTH_SOFT:
+ case AL_SOURCE_RADIUS:
if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
*values = (ALint64)dvals[0];
return err;
- /* 2x float/double */
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- case AL_BYTE_RW_OFFSETS_SOFT:
- if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
- {
- values[0] = (ALint64)dvals[0];
- values[1] = (ALint64)dvals[1];
- }
- return err;
-
/* 3x float/double */
case AL_POSITION:
case AL_VELOCITY:
@@ -1416,14 +1633,14 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp
case AL_SOURCE_STATE:
case AL_BUFFERS_QUEUED:
case AL_BUFFERS_PROCESSED:
- case AL_BYTE_LENGTH_SOFT:
- case AL_SAMPLE_LENGTH_SOFT:
case AL_SOURCE_TYPE:
case AL_DIRECT_FILTER_GAINHF_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DIRECT_CHANNELS_SOFT:
case AL_DISTANCE_MODEL:
+ case AL_SOURCE_RESAMPLER_SOFT:
+ case AL_SOURCE_SPATIALIZE_SOFT:
if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
*values = ivals[0];
return err;
@@ -1446,11 +1663,15 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp
return err;
case AL_SEC_OFFSET_LATENCY_SOFT:
+ case AL_SEC_OFFSET_CLOCK_SOFT:
break; /* Double only */
+ case AL_STEREO_ANGLES:
+ break; /* Float/double only */
}
ERR("Unexpected property: 0x%04x\n", prop);
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
+ SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x",
+ prop);
}
@@ -1458,40 +1679,23 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
{
ALCcontext *context;
ALsizei cur = 0;
- ALenum err;
context = GetContextRef();
if(!context) return;
if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- for(cur = 0;cur < n;cur++)
+ alSetError(context, AL_INVALID_VALUE, "Generating %d sources", n);
+ else for(cur = 0;cur < n;cur++)
{
- ALsource *source = al_calloc(16, sizeof(ALsource));
+ ALsource *source = AllocSource(context);
if(!source)
{
alDeleteSources(cur, sources);
- SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
- }
- InitSourceParams(source);
-
- err = NewThunkEntry(&source->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
- if(err != AL_NO_ERROR)
- {
- FreeThunkEntry(source->id);
- memset(source, 0, sizeof(ALsource));
- al_free(source);
-
- alDeleteSources(cur, sources);
- SET_ERROR_AND_GOTO(context, err, done);
+ break;
}
-
sources[cur] = source->id;
}
-done:
ALCcontext_DecRef(context);
}
@@ -1499,64 +1703,30 @@ done:
AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
{
ALCcontext *context;
- ALbufferlistitem *BufferList;
ALsource *Source;
- ALsizei i, j;
+ ALsizei i;
context = GetContextRef();
if(!context) return;
+ LockSourceList(context);
if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d sources", n);
/* Check that all Sources are valid */
for(i = 0;i < n;i++)
{
if(LookupSource(context, sources[i]) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
}
for(i = 0;i < n;i++)
{
- ALvoice *voice, *voice_end;
-
- if((Source=RemoveSource(context, sources[i])) == NULL)
- continue;
- FreeThunkEntry(Source->id);
-
- LockContext(context);
- voice = context->Voices;
- voice_end = voice + context->VoiceCount;
- while(voice != voice_end)
- {
- ALsource *old = Source;
- if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
- break;
- voice++;
- }
- UnlockContext(context);
-
- BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
- while(BufferList != NULL)
- {
- ALbufferlistitem *next = BufferList->next;
- if(BufferList->buffer != NULL)
- DecrementRef(&BufferList->buffer->ref);
- free(BufferList);
- BufferList = next;
- }
-
- for(j = 0;j < MAX_SENDS;++j)
- {
- if(Source->Send[j].Slot)
- DecrementRef(&Source->Send[j].Slot->ref);
- Source->Send[j].Slot = NULL;
- }
-
- memset(Source, 0, sizeof(*Source));
- al_free(Source);
+ if((Source=LookupSource(context, sources[i])) != NULL)
+ FreeSource(context, Source);
}
done:
+ UnlockSourceList(context);
ALCcontext_DecRef(context);
}
@@ -1569,7 +1739,9 @@ AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
context = GetContextRef();
if(!context) return AL_FALSE;
+ LockSourceList(context);
ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
+ UnlockSourceList(context);
ALCcontext_DecRef(context);
@@ -1585,12 +1757,16 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(FloatValsByProp(param) == 1))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param);
else
SetSourcefv(Source, Context, param, &value);
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1603,15 +1779,19 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(FloatValsByProp(param) == 3))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param);
else
{
ALfloat fvals[3] = { value1, value2, value3 };
SetSourcefv(Source, Context, param, fvals);
}
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1624,14 +1804,18 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!values)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(FloatValsByProp(param) > 0))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param);
else
SetSourcefv(Source, Context, param, values);
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1645,15 +1829,19 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(DoubleValsByProp(param) == 1))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param);
else
{
ALfloat fval = (ALfloat)value;
SetSourcefv(Source, Context, param, &fval);
}
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1666,15 +1854,19 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(DoubleValsByProp(param) == 3))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param);
else
{
ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
SetSourcefv(Source, Context, param, fvals);
}
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1688,12 +1880,14 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!values)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param);
else
{
ALfloat fvals[6];
@@ -1703,6 +1897,8 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo
fvals[i] = (ALfloat)values[i];
SetSourcefv(Source, Context, param, fvals);
}
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1716,12 +1912,16 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(IntValsByProp(param) == 1))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param);
else
SetSourceiv(Source, Context, param, &value);
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1734,15 +1934,19 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(IntValsByProp(param) == 3))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param);
else
{
ALint ivals[3] = { value1, value2, value3 };
SetSourceiv(Source, Context, param, ivals);
}
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1755,14 +1959,18 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!values)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(IntValsByProp(param) > 0))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param);
else
SetSourceiv(Source, Context, param, values);
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1776,12 +1984,16 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(Int64ValsByProp(param) == 1))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param);
else
SetSourcei64v(Source, Context, param, &value);
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1794,15 +2006,19 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(Int64ValsByProp(param) == 3))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param);
else
{
ALint64SOFT i64vals[3] = { value1, value2, value3 };
SetSourcei64v(Source, Context, param, i64vals);
}
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1815,14 +2031,18 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin
Context = GetContextRef();
if(!Context) return;
+ almtx_lock(&Context->PropLock);
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!values)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(Int64ValsByProp(param) > 0))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param);
else
SetSourcei64v(Source, Context, param, values);
+ UnlockSourceList(Context);
+ almtx_unlock(&Context->PropLock);
ALCcontext_DecRef(Context);
}
@@ -1836,18 +2056,20 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!value)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(FloatValsByProp(param) == 1))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param);
else
{
ALdouble dval;
if(GetSourcedv(Source, Context, param, &dval))
*value = (ALfloat)dval;
}
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -1861,12 +2083,13 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(value1 && value2 && value3))
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(FloatValsByProp(param) == 3))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param);
else
{
ALdouble dvals[3];
@@ -1877,6 +2100,7 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va
*value3 = (ALfloat)dvals[2];
}
}
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -1891,12 +2115,13 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!values)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param);
else
{
ALdouble dvals[6];
@@ -1907,6 +2132,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va
values[i] = (ALfloat)dvals[i];
}
}
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -1920,14 +2146,16 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!value)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(DoubleValsByProp(param) == 1))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param);
else
GetSourcedv(Source, Context, param, value);
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -1940,12 +2168,13 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(value1 && value2 && value3))
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(DoubleValsByProp(param) == 3))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param);
else
{
ALdouble dvals[3];
@@ -1956,6 +2185,7 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble
*value3 = dvals[2];
}
}
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -1968,14 +2198,16 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!values)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(DoubleValsByProp(param) > 0))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param);
else
GetSourcedv(Source, Context, param, values);
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -1989,14 +2221,16 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!value)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(IntValsByProp(param) == 1))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param);
else
GetSourceiv(Source, Context, param, value);
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -2010,12 +2244,13 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(value1 && value2 && value3))
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(IntValsByProp(param) == 3))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param);
else
{
ALint ivals[3];
@@ -2026,6 +2261,7 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1
*value3 = ivals[2];
}
}
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -2039,14 +2275,16 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!values)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(IntValsByProp(param) > 0))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param);
else
GetSourceiv(Source, Context, param, values);
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -2060,14 +2298,16 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!value)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(Int64ValsByProp(param) == 1))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param);
else
GetSourcei64v(Source, Context, param, value);
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -2080,12 +2320,13 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!(value1 && value2 && value3))
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(Int64ValsByProp(param) == 3))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param);
else
{
ALint64 i64vals[3];
@@ -2096,6 +2337,7 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64
*value3 = i64vals[2];
}
}
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -2108,14 +2350,16 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64
Context = GetContextRef();
if(!Context) return;
+ LockSourceList(Context);
if((Source=LookupSource(Context, source)) == NULL)
- alSetError(Context, AL_INVALID_NAME);
+ alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
else if(!values)
- alSetError(Context, AL_INVALID_VALUE);
+ alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
else if(!(Int64ValsByProp(param) > 0))
- alSetError(Context, AL_INVALID_ENUM);
+ alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param);
else
GetSourcei64v(Source, Context, param, values);
+ UnlockSourceList(Context);
ALCcontext_DecRef(Context);
}
@@ -2128,49 +2372,183 @@ AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
{
ALCcontext *context;
+ ALCdevice *device;
ALsource *source;
- ALsizei i;
+ ALvoice *voice;
+ ALsizei i, j;
context = GetContextRef();
if(!context) return;
+ LockSourceList(context);
if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Playing %d sources", n);
for(i = 0;i < n;i++)
{
if(!LookupSource(context, sources[i]))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
}
- LockContext(context);
- while(n > context->MaxVoices-context->VoiceCount)
+ device = context->Device;
+ ALCdevice_Lock(device);
+ /* If the device is disconnected, go right to stopped. */
+ if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
{
- ALvoice *temp = NULL;
- ALsizei newcount;
-
- newcount = context->MaxVoices << 1;
- if(newcount > 0)
- temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
- if(!temp)
+ /* TODO: Send state change event? */
+ for(i = 0;i < n;i++)
{
- UnlockContext(context);
- SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
+ source = LookupSource(context, sources[i]);
+ source->OffsetType = AL_NONE;
+ source->Offset = 0.0;
+ source->state = AL_STOPPED;
}
- memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
+ ALCdevice_Unlock(device);
+ goto done;
+ }
- context->Voices = temp;
- context->MaxVoices = newcount;
+ while(n > context->MaxVoices-context->VoiceCount)
+ {
+ ALsizei newcount = context->MaxVoices << 1;
+ if(context->MaxVoices >= newcount)
+ {
+ ALCdevice_Unlock(device);
+ SETERR_GOTO(context, AL_OUT_OF_MEMORY, done,
+ "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount);
+ }
+ AllocateVoices(context, newcount, device->NumAuxSends);
}
for(i = 0;i < n;i++)
{
+ ALbufferlistitem *BufferList;
+ bool start_fading = false;
+ ALint vidx = -1;
+
source = LookupSource(context, sources[i]);
- if(context->DeferUpdates) source->new_state = AL_PLAYING;
- else SetSourceState(source, context, AL_PLAYING);
+ /* Check that there is a queue containing at least one valid, non zero
+ * length buffer.
+ */
+ BufferList = source->queue;
+ while(BufferList && BufferList->max_samples == 0)
+ BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
+
+ /* If there's nothing to play, go right to stopped. */
+ if(UNLIKELY(!BufferList))
+ {
+ /* NOTE: A source without any playable buffers should not have an
+ * ALvoice since it shouldn't be in a playing or paused state. So
+ * there's no need to look up its voice and clear the source.
+ */
+ ALenum oldstate = GetSourceState(source, NULL);
+ source->OffsetType = AL_NONE;
+ source->Offset = 0.0;
+ if(oldstate != AL_STOPPED)
+ {
+ source->state = AL_STOPPED;
+ SendStateChangeEvent(context, source->id, AL_STOPPED);
+ }
+ continue;
+ }
+
+ voice = GetSourceVoice(source, context);
+ switch(GetSourceState(source, voice))
+ {
+ case AL_PLAYING:
+ assert(voice != NULL);
+ /* A source that's already playing is restarted from the beginning. */
+ ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release);
+ continue;
+
+ case AL_PAUSED:
+ assert(voice != NULL);
+ /* A source that's paused simply resumes. */
+ ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
+ source->state = AL_PLAYING;
+ SendStateChangeEvent(context, source->id, AL_PLAYING);
+ continue;
+
+ default:
+ break;
+ }
+
+ /* Look for an unused voice to play this source with. */
+ assert(voice == NULL);
+ for(j = 0;j < context->VoiceCount;j++)
+ {
+ if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL)
+ {
+ vidx = j;
+ break;
+ }
+ }
+ if(vidx == -1)
+ vidx = context->VoiceCount++;
+ voice = context->Voices[vidx];
+ ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
+
+ ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire);
+ UpdateSourceProps(source, voice, device->NumAuxSends, context);
+
+ /* A source that's not playing or paused has any offset applied when it
+ * starts playing.
+ */
+ if(source->Looping)
+ ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed);
+ else
+ ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed);
+ if(ApplyOffset(source, voice) != AL_FALSE)
+ start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 ||
+ ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 ||
+ ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList;
+
+ for(j = 0;j < BufferList->num_buffers;j++)
+ {
+ ALbuffer *buffer = BufferList->buffers[j];
+ if(buffer)
+ {
+ voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
+ voice->SampleSize = BytesFromFmt(buffer->FmtType);
+ break;
+ }
+ }
+
+ /* Clear previous samples. */
+ memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
+
+ /* Clear the stepping value so the mixer knows not to mix this until
+ * the update gets applied.
+ */
+ voice->Step = 0;
+
+ voice->Flags = start_fading ? VOICE_IS_FADING : 0;
+ if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC;
+ memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels);
+ for(j = 0;j < device->NumAuxSends;j++)
+ memset(voice->Send[j].Params, 0, sizeof(voice->Send[j].Params[0])*voice->NumChannels);
+ if(device->AvgSpeakerDist > 0.0f)
+ {
+ ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
+ (device->AvgSpeakerDist * device->Frequency);
+ for(j = 0;j < voice->NumChannels;j++)
+ NfcFilterCreate(&voice->Direct.Params[j].NFCtrlFilter, 0.0f, w1);
+ }
+
+ ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
+ source->state = AL_PLAYING;
+ source->VoiceIdx = vidx;
+
+ SendStateChangeEvent(context, source->id, AL_PLAYING);
}
- UnlockContext(context);
+ ALCdevice_Unlock(device);
done:
+ UnlockSourceList(context);
ALCcontext_DecRef(context);
}
@@ -2181,30 +2559,40 @@ AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
{
ALCcontext *context;
+ ALCdevice *device;
ALsource *source;
+ ALvoice *voice;
ALsizei i;
context = GetContextRef();
if(!context) return;
+ LockSourceList(context);
if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Pausing %d sources", n);
for(i = 0;i < n;i++)
{
if(!LookupSource(context, sources[i]))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
}
- LockContext(context);
+ device = context->Device;
+ ALCdevice_Lock(device);
for(i = 0;i < n;i++)
{
source = LookupSource(context, sources[i]);
- if(context->DeferUpdates) source->new_state = AL_PAUSED;
- else SetSourceState(source, context, AL_PAUSED);
+ if((voice=GetSourceVoice(source, context)) != NULL)
+ ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
+ if(GetSourceState(source, voice) == AL_PLAYING)
+ {
+ source->state = AL_PAUSED;
+ SendStateChangeEvent(context, source->id, AL_PAUSED);
+ }
}
- UnlockContext(context);
+ ALCdevice_Unlock(device);
done:
+ UnlockSourceList(context);
ALCcontext_DecRef(context);
}
@@ -2215,30 +2603,48 @@ AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
{
ALCcontext *context;
+ ALCdevice *device;
ALsource *source;
+ ALvoice *voice;
ALsizei i;
context = GetContextRef();
if(!context) return;
+ LockSourceList(context);
if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Stopping %d sources", n);
for(i = 0;i < n;i++)
{
if(!LookupSource(context, sources[i]))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
}
- LockContext(context);
+ device = context->Device;
+ ALCdevice_Lock(device);
for(i = 0;i < n;i++)
{
+ ALenum oldstate;
source = LookupSource(context, sources[i]);
- source->new_state = AL_NONE;
- SetSourceState(source, context, AL_STOPPED);
+ if((voice=GetSourceVoice(source, context)) != NULL)
+ {
+ ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
+ voice = NULL;
+ }
+ oldstate = GetSourceState(source, voice);
+ if(oldstate != AL_INITIAL && oldstate != AL_STOPPED)
+ {
+ source->state = AL_STOPPED;
+ SendStateChangeEvent(context, source->id, AL_STOPPED);
+ }
+ source->OffsetType = AL_NONE;
+ source->Offset = 0.0;
}
- UnlockContext(context);
+ ALCdevice_Unlock(device);
done:
+ UnlockSourceList(context);
ALCcontext_DecRef(context);
}
@@ -2249,30 +2655,46 @@ AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
{
ALCcontext *context;
+ ALCdevice *device;
ALsource *source;
+ ALvoice *voice;
ALsizei i;
context = GetContextRef();
if(!context) return;
+ LockSourceList(context);
if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Rewinding %d sources", n);
for(i = 0;i < n;i++)
{
if(!LookupSource(context, sources[i]))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
}
- LockContext(context);
+ device = context->Device;
+ ALCdevice_Lock(device);
for(i = 0;i < n;i++)
{
source = LookupSource(context, sources[i]);
- source->new_state = AL_NONE;
- SetSourceState(source, context, AL_INITIAL);
+ if((voice=GetSourceVoice(source, context)) != NULL)
+ {
+ ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
+ voice = NULL;
+ }
+ if(GetSourceState(source, voice) != AL_INITIAL)
+ {
+ source->state = AL_INITIAL;
+ SendStateChangeEvent(context, source->id, AL_INITIAL);
+ }
+ source->OffsetType = AL_NONE;
+ source->Offset = 0.0;
}
- UnlockContext(context);
+ ALCdevice_Unlock(device);
done:
+ UnlockSourceList(context);
ALCcontext_DecRef(context);
}
@@ -2295,133 +2717,122 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu
device = context->Device;
+ LockSourceList(context);
if(!(nb >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffers", nb);
if((source=LookupSource(context, src)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src);
- WriteLock(&source->queue_lock);
if(source->SourceType == AL_STATIC)
{
- WriteUnlock(&source->queue_lock);
/* Can't queue on a Static Source */
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src);
}
/* Check for a valid Buffer, for its frequency and format */
- BufferList = ATOMIC_LOAD(&source->queue);
+ BufferList = source->queue;
while(BufferList)
{
- if(BufferList->buffer)
+ for(i = 0;i < BufferList->num_buffers;i++)
{
- BufferFmt = BufferList->buffer;
- break;
+ if((BufferFmt=BufferList->buffers[i]) != NULL)
+ break;
}
- BufferList = BufferList->next;
+ if(BufferFmt) break;
+ BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
}
+ LockBufferList(device);
BufferListStart = NULL;
BufferList = NULL;
for(i = 0;i < nb;i++)
{
ALbuffer *buffer = NULL;
if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
- {
- WriteUnlock(&source->queue_lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
- }
+ SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u",
+ buffers[i]);
if(!BufferListStart)
{
- BufferListStart = malloc(sizeof(ALbufferlistitem));
- BufferListStart->buffer = buffer;
- BufferListStart->next = NULL;
- BufferListStart->prev = NULL;
+ BufferListStart = al_calloc(DEF_ALIGN,
+ FAM_SIZE(ALbufferlistitem, buffers, 1));
BufferList = BufferListStart;
}
else
{
- BufferList->next = malloc(sizeof(ALbufferlistitem));
- BufferList->next->buffer = buffer;
- BufferList->next->next = NULL;
- BufferList->next->prev = BufferList;
- BufferList = BufferList->next;
+ ALbufferlistitem *item = al_calloc(DEF_ALIGN,
+ FAM_SIZE(ALbufferlistitem, buffers, 1));
+ ATOMIC_STORE(&BufferList->next, item, almemory_order_relaxed);
+ BufferList = item;
}
+ ATOMIC_INIT(&BufferList->next, NULL);
+ BufferList->max_samples = buffer ? buffer->SampleLen : 0;
+ BufferList->num_buffers = 1;
+ BufferList->buffers[0] = buffer;
if(!buffer) continue;
- /* Hold a read lock on each buffer being queued while checking all
- * provided buffers. This is done so other threads don't see an extra
- * reference on some buffers if this operation ends up failing. */
- ReadLock(&buffer->lock);
IncrementRef(&buffer->ref);
+ if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
+ SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error,
+ "Queueing non-persistently mapped buffer %u", buffer->id);
+
if(BufferFmt == NULL)
- {
BufferFmt = buffer;
-
- source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
- source->SampleSize = BytesFromFmt(buffer->FmtType);
- }
else if(BufferFmt->Frequency != buffer->Frequency ||
- BufferFmt->OriginalChannels != buffer->OriginalChannels ||
+ BufferFmt->FmtChannels != buffer->FmtChannels ||
BufferFmt->OriginalType != buffer->OriginalType)
{
- WriteUnlock(&source->queue_lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
+ alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format");
buffer_error:
/* A buffer failed (invalid ID or format), so unlock and release
* each buffer we had. */
- while(BufferList != NULL)
+ while(BufferListStart)
{
- ALbufferlistitem *prev = BufferList->prev;
- if((buffer=BufferList->buffer) != NULL)
+ ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next,
+ almemory_order_relaxed);
+ for(i = 0;i < BufferListStart->num_buffers;i++)
{
- DecrementRef(&buffer->ref);
- ReadUnlock(&buffer->lock);
+ if((buffer=BufferListStart->buffers[i]) != NULL)
+ DecrementRef(&buffer->ref);
}
- free(BufferList);
- BufferList = prev;
+ al_free(BufferListStart);
+ BufferListStart = next;
}
+ UnlockBufferList(device);
goto done;
}
}
- /* All buffers good, unlock them now. */
- while(BufferList != NULL)
- {
- ALbuffer *buffer = BufferList->buffer;
- if(buffer) ReadUnlock(&buffer->lock);
- BufferList = BufferList->prev;
- }
+ /* All buffers good. */
+ UnlockBufferList(device);
/* Source is now streaming */
source->SourceType = AL_STREAMING;
- BufferList = NULL;
- if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
+ if(!(BufferList=source->queue))
+ source->queue = BufferListStart;
+ else
{
- /* Queue head is not NULL, append to the end of the queue */
- while(BufferList->next != NULL)
- BufferList = BufferList->next;
-
- BufferListStart->prev = BufferList;
- BufferList->next = BufferListStart;
+ ALbufferlistitem *next;
+ while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL)
+ BufferList = next;
+ ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release);
}
- BufferList = NULL;
- ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
- WriteUnlock(&source->queue_lock);
done:
+ UnlockSourceList(context);
ALCcontext_DecRef(context);
}
-AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
+AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers)
{
+ ALCdevice *device;
ALCcontext *context;
+ ALbufferlistitem *BufferListStart;
+ ALbufferlistitem *BufferList;
+ ALbuffer *BufferFmt = NULL;
ALsource *source;
- ALbufferlistitem *NewHead;
- ALbufferlistitem *OldHead;
- ALbufferlistitem *Current;
ALsizei i;
if(nb == 0)
@@ -2430,85 +2841,218 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint
context = GetContextRef();
if(!context) return;
- if(!(nb >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ device = context->Device;
+ LockSourceList(context);
+ if(!(nb >= 0 && nb < 16))
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffer layers", nb);
if((source=LookupSource(context, src)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src);
- WriteLock(&source->queue_lock);
- /* Find the new buffer queue head */
- NewHead = ATOMIC_LOAD(&source->queue);
- Current = ATOMIC_LOAD(&source->current_buffer);
- for(i = 0;i < nb && NewHead;i++)
+ if(source->SourceType == AL_STATIC)
{
- if(NewHead == Current)
- break;
- NewHead = NewHead->next;
+ /* Can't queue on a Static Source */
+ SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src);
}
- if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
+
+ /* Check for a valid Buffer, for its frequency and format */
+ BufferList = source->queue;
+ while(BufferList)
{
- WriteUnlock(&source->queue_lock);
- /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(i = 0;i < BufferList->num_buffers;i++)
+ {
+ if((BufferFmt=BufferList->buffers[i]) != NULL)
+ break;
+ }
+ if(BufferFmt) break;
+ BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
}
- /* Swap it, and cut the new head from the old. */
- OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
- if(NewHead)
+ LockBufferList(device);
+ BufferListStart = al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, nb));
+ BufferList = BufferListStart;
+ ATOMIC_INIT(&BufferList->next, NULL);
+ BufferList->max_samples = 0;
+ BufferList->num_buffers = 0;
+ for(i = 0;i < nb;i++)
{
- ALCdevice *device = context->Device;
- ALbufferlistitem *OldTail = NewHead->prev;
- uint count;
+ ALbuffer *buffer = NULL;
+ if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
+ SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u",
+ buffers[i]);
- /* Cut the new head's link back to the old body. The mixer is robust
- * enough to handle the link back going away. Once the active mix (if
- * any) is complete, it's safe to finish cutting the old tail from the
- * new head. */
- NewHead->prev = NULL;
- if(((count=ReadRef(&device->MixCount))&1) != 0)
+ BufferList->buffers[BufferList->num_buffers++] = buffer;
+ if(!buffer) continue;
+
+ IncrementRef(&buffer->ref);
+
+ BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen);
+
+ if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
+ SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error,
+ "Queueing non-persistently mapped buffer %u", buffer->id);
+
+ if(BufferFmt == NULL)
+ BufferFmt = buffer;
+ else if(BufferFmt->Frequency != buffer->Frequency ||
+ BufferFmt->FmtChannels != buffer->FmtChannels ||
+ BufferFmt->OriginalType != buffer->OriginalType)
{
- while(count == ReadRef(&device->MixCount))
- althrd_yield();
+ alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format");
+
+ buffer_error:
+ /* A buffer failed (invalid ID or format), so unlock and release
+ * each buffer we had. */
+ while(BufferListStart)
+ {
+ ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next,
+ almemory_order_relaxed);
+ for(i = 0;i < BufferListStart->num_buffers;i++)
+ {
+ if((buffer=BufferListStart->buffers[i]) != NULL)
+ DecrementRef(&buffer->ref);
+ }
+ al_free(BufferListStart);
+ BufferListStart = next;
+ }
+ UnlockBufferList(device);
+ goto done;
}
- OldTail->next = NULL;
}
- WriteUnlock(&source->queue_lock);
+ /* All buffers good. */
+ UnlockBufferList(device);
+
+ /* Source is now streaming */
+ source->SourceType = AL_STREAMING;
- while(OldHead != NULL)
+ if(!(BufferList=source->queue))
+ source->queue = BufferListStart;
+ else
{
- ALbufferlistitem *next = OldHead->next;
- ALbuffer *buffer = OldHead->buffer;
+ ALbufferlistitem *next;
+ while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL)
+ BufferList = next;
+ ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release);
+ }
- if(!buffer)
- *(buffers++) = 0;
- else
+done:
+ UnlockSourceList(context);
+ ALCcontext_DecRef(context);
+}
+
+AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
+{
+ ALCcontext *context;
+ ALsource *source;
+ ALbufferlistitem *BufferList;
+ ALbufferlistitem *Current;
+ ALvoice *voice;
+ ALsizei i;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ LockSourceList(context);
+ if(!(nb >= 0))
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing %d buffers", nb);
+ if((source=LookupSource(context, src)) == NULL)
+ SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src);
+
+ /* Nothing to unqueue. */
+ if(nb == 0) goto done;
+
+ if(source->Looping)
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from looping source %u", src);
+ if(source->SourceType != AL_STREAMING)
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from a non-streaming source %u",
+ src);
+
+ /* Make sure enough buffers have been processed to unqueue. */
+ BufferList = source->queue;
+ Current = NULL;
+ if((voice=GetSourceVoice(source, context)) != NULL)
+ Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
+ else if(source->state == AL_INITIAL)
+ Current = BufferList;
+ if(BufferList == Current)
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers");
+
+ i = BufferList->num_buffers;
+ while(i < nb)
+ {
+ /* If the next bufferlist to check is NULL or is the current one, it's
+ * trying to unqueue pending buffers.
+ */
+ ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
+ if(!next || next == Current)
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers");
+ BufferList = next;
+
+ i += BufferList->num_buffers;
+ }
+
+ while(nb > 0)
+ {
+ ALbufferlistitem *head = source->queue;
+ ALbufferlistitem *next = ATOMIC_LOAD(&head->next, almemory_order_relaxed);
+ for(i = 0;i < head->num_buffers && nb > 0;i++,nb--)
{
- *(buffers++) = buffer->id;
- DecrementRef(&buffer->ref);
+ ALbuffer *buffer = head->buffers[i];
+ if(!buffer)
+ *(buffers++) = 0;
+ else
+ {
+ *(buffers++) = buffer->id;
+ DecrementRef(&buffer->ref);
+ }
+ }
+ if(i < head->num_buffers)
+ {
+ /* This head has some buffers left over, so move them to the front
+ * and update the sample and buffer count.
+ */
+ ALsizei max_length = 0;
+ ALsizei j = 0;
+ while(i < head->num_buffers)
+ {
+ ALbuffer *buffer = head->buffers[i++];
+ if(buffer) max_length = maxi(max_length, buffer->SampleLen);
+ head->buffers[j++] = buffer;
+ }
+ head->max_samples = max_length;
+ head->num_buffers = j;
+ break;
}
- free(OldHead);
- OldHead = next;
+ /* Otherwise, free this item and set the source queue head to the next
+ * one.
+ */
+ al_free(head);
+ source->queue = next;
}
done:
+ UnlockSourceList(context);
ALCcontext_DecRef(context);
}
-static ALvoid InitSourceParams(ALsource *Source)
+static void InitSourceParams(ALsource *Source, ALsizei num_sends)
{
- ALuint i;
-
- RWLockInit(&Source->queue_lock);
+ ALsizei i;
Source->InnerAngle = 360.0f;
Source->OuterAngle = 360.0f;
Source->Pitch = 1.0f;
- aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
- aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
- aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
+ Source->Position[0] = 0.0f;
+ Source->Position[1] = 0.0f;
+ Source->Position[2] = 0.0f;
+ Source->Velocity[0] = 0.0f;
+ Source->Velocity[1] = 0.0f;
+ Source->Velocity[2] = 0.0f;
+ Source->Direction[0] = 0.0f;
+ Source->Direction[1] = 0.0f;
+ Source->Direction[2] = 0.0f;
Source->Orientation[0][0] = 0.0f;
Source->Orientation[0][1] = 0.0f;
Source->Orientation[0][2] = -1.0f;
@@ -2517,8 +3061,7 @@ static ALvoid InitSourceParams(ALsource *Source)
Source->Orientation[1][2] = 0.0f;
Source->RefDistance = 1.0f;
Source->MaxDistance = FLT_MAX;
- Source->RollOffFactor = 1.0f;
- Source->Looping = AL_FALSE;
+ Source->RolloffFactor = 1.0f;
Source->Gain = 1.0f;
Source->MinGain = 0.0f;
Source->MaxGain = 1.0f;
@@ -2531,27 +3074,27 @@ static ALvoid InitSourceParams(ALsource *Source)
Source->AirAbsorptionFactor = 0.0f;
Source->RoomRolloffFactor = 0.0f;
Source->DopplerFactor = 1.0f;
- Source->DirectChannels = AL_FALSE;
-
- Source->Radius = 0.0f;
-
+ Source->HeadRelative = AL_FALSE;
+ Source->Looping = AL_FALSE;
Source->DistanceModel = DefaultDistanceModel;
+ Source->Resampler = ResamplerDefault;
+ Source->DirectChannels = AL_FALSE;
+ Source->Spatialize = SpatializeAuto;
- Source->state = AL_INITIAL;
- Source->new_state = AL_NONE;
- Source->SourceType = AL_UNDETERMINED;
- Source->Offset = -1.0;
+ Source->StereoPan[0] = DEG2RAD( 30.0f);
+ Source->StereoPan[1] = DEG2RAD(-30.0f);
- ATOMIC_INIT(&Source->queue, NULL);
- ATOMIC_INIT(&Source->current_buffer, NULL);
+ Source->Radius = 0.0f;
Source->Direct.Gain = 1.0f;
Source->Direct.GainHF = 1.0f;
Source->Direct.HFReference = LOWPASSFREQREF;
Source->Direct.GainLF = 1.0f;
Source->Direct.LFReference = HIGHPASSFREQREF;
- for(i = 0;i < MAX_SENDS;i++)
+ Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
+ for(i = 0;i < num_sends;i++)
{
+ Source->Send[i].Slot = NULL;
Source->Send[i].Gain = 1.0f;
Source->Send[i].GainHF = 1.0f;
Source->Send[i].HFReference = LOWPASSFREQREF;
@@ -2559,179 +3102,202 @@ static ALvoid InitSourceParams(ALsource *Source)
Source->Send[i].LFReference = HIGHPASSFREQREF;
}
- ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
-}
+ Source->Offset = 0.0;
+ Source->OffsetType = AL_NONE;
+ Source->SourceType = AL_UNDETERMINED;
+ Source->state = AL_INITIAL;
+ Source->queue = NULL;
-/* SetSourceState
- *
- * Sets the source's new play state given its current state.
- */
-ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
+ /* No way to do an 'init' here, so just test+set with relaxed ordering and
+ * ignore the test.
+ */
+ ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed);
+
+ Source->VoiceIdx = -1;
+}
+
+static void DeinitSource(ALsource *source, ALsizei num_sends)
{
- WriteLock(&Source->queue_lock);
- if(state == AL_PLAYING)
- {
- ALCdevice *device = Context->Device;
- ALbufferlistitem *BufferList;
- ALboolean discontinuity;
- ALvoice *voice = NULL;
- ALsizei i;
+ ALbufferlistitem *BufferList;
+ ALsizei i;
- /* Check that there is a queue containing at least one valid, non zero
- * length Buffer. */
- BufferList = ATOMIC_LOAD(&Source->queue);
- while(BufferList)
+ BufferList = source->queue;
+ while(BufferList != NULL)
+ {
+ ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
+ for(i = 0;i < BufferList->num_buffers;i++)
{
- ALbuffer *buffer;
- if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
- break;
- BufferList = BufferList->next;
+ if(BufferList->buffers[i] != NULL)
+ DecrementRef(&BufferList->buffers[i]->ref);
}
+ al_free(BufferList);
+ BufferList = next;
+ }
+ source->queue = NULL;
- if(Source->state != AL_PAUSED)
- {
- Source->state = AL_PLAYING;
- Source->position = 0;
- Source->position_fraction = 0;
- ATOMIC_STORE(&Source->current_buffer, BufferList);
- discontinuity = AL_TRUE;
- }
- else
+ if(source->Send)
+ {
+ for(i = 0;i < num_sends;i++)
{
- Source->state = AL_PLAYING;
- discontinuity = AL_FALSE;
+ if(source->Send[i].Slot)
+ DecrementRef(&source->Send[i].Slot->ref);
+ source->Send[i].Slot = NULL;
}
+ al_free(source->Send);
+ source->Send = NULL;
+ }
+}
- // Check if an Offset has been set
- if(Source->Offset >= 0.0)
- {
- ApplyOffset(Source);
- /* discontinuity = AL_TRUE;??? */
- }
+static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context)
+{
+ struct ALvoiceProps *props;
+ ALsizei i;
- /* If there's nothing to play, or device is disconnected, go right to
- * stopped */
- if(!BufferList || !device->Connected)
- goto do_stop;
+ /* Get an unused property container, or allocate a new one as needed. */
+ props = ATOMIC_LOAD(&context->FreeVoiceProps, almemory_order_acquire);
+ if(!props)
+ props = al_calloc(16, FAM_SIZE(struct ALvoiceProps, Send, num_sends));
+ else
+ {
+ struct ALvoiceProps *next;
+ do {
+ next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
+ } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeVoiceProps, &props, next,
+ almemory_order_acq_rel, almemory_order_acquire) == 0);
+ }
- /* Make sure this source isn't already active, while looking for an
- * unused active source slot to put it in. */
- for(i = 0;i < Context->VoiceCount;i++)
- {
- ALsource *old = Source;
- if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
- {
- if(voice == NULL)
- {
- voice = &Context->Voices[i];
- voice->Source = Source;
- }
- break;
- }
- old = NULL;
- if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
- voice = &Context->Voices[i];
- }
- if(voice == NULL)
- {
- voice = &Context->Voices[Context->VoiceCount++];
- voice->Source = Source;
- }
+ /* Copy in current property values. */
+ props->Pitch = source->Pitch;
+ props->Gain = source->Gain;
+ props->OuterGain = source->OuterGain;
+ props->MinGain = source->MinGain;
+ props->MaxGain = source->MaxGain;
+ props->InnerAngle = source->InnerAngle;
+ props->OuterAngle = source->OuterAngle;
+ props->RefDistance = source->RefDistance;
+ props->MaxDistance = source->MaxDistance;
+ props->RolloffFactor = source->RolloffFactor;
+ for(i = 0;i < 3;i++)
+ props->Position[i] = source->Position[i];
+ for(i = 0;i < 3;i++)
+ props->Velocity[i] = source->Velocity[i];
+ for(i = 0;i < 3;i++)
+ props->Direction[i] = source->Direction[i];
+ for(i = 0;i < 2;i++)
+ {
+ ALsizei j;
+ for(j = 0;j < 3;j++)
+ props->Orientation[i][j] = source->Orientation[i][j];
+ }
+ props->HeadRelative = source->HeadRelative;
+ props->DistanceModel = source->DistanceModel;
+ props->Resampler = source->Resampler;
+ props->DirectChannels = source->DirectChannels;
+ props->SpatializeMode = source->Spatialize;
- /* Clear previous samples if playback is discontinuous. */
- if(discontinuity)
- memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
+ props->DryGainHFAuto = source->DryGainHFAuto;
+ props->WetGainAuto = source->WetGainAuto;
+ props->WetGainHFAuto = source->WetGainHFAuto;
+ props->OuterGainHF = source->OuterGainHF;
- voice->Direct.Moving = AL_FALSE;
- voice->Direct.Counter = 0;
- for(i = 0;i < MAX_INPUT_CHANNELS;i++)
- {
- ALsizei j;
- for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
- voice->Direct.Hrtf[i].State.History[j] = 0.0f;
- for(j = 0;j < HRIR_LENGTH;j++)
- {
- voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
- voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
- }
- }
- for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
- {
- voice->Send[i].Moving = AL_FALSE;
- voice->Send[i].Counter = 0;
- }
+ props->AirAbsorptionFactor = source->AirAbsorptionFactor;
+ props->RoomRolloffFactor = source->RoomRolloffFactor;
+ props->DopplerFactor = source->DopplerFactor;
- if(BufferList->buffer->FmtChannels == FmtMono)
- voice->Update = CalcSourceParams;
- else
- voice->Update = CalcNonAttnSourceParams;
+ props->StereoPan[0] = source->StereoPan[0];
+ props->StereoPan[1] = source->StereoPan[1];
- ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
- }
- else if(state == AL_PAUSED)
+ props->Radius = source->Radius;
+
+ props->Direct.Gain = source->Direct.Gain;
+ props->Direct.GainHF = source->Direct.GainHF;
+ props->Direct.HFReference = source->Direct.HFReference;
+ props->Direct.GainLF = source->Direct.GainLF;
+ props->Direct.LFReference = source->Direct.LFReference;
+
+ for(i = 0;i < num_sends;i++)
{
- if(Source->state == AL_PLAYING)
- Source->state = AL_PAUSED;
+ props->Send[i].Slot = source->Send[i].Slot;
+ props->Send[i].Gain = source->Send[i].Gain;
+ props->Send[i].GainHF = source->Send[i].GainHF;
+ props->Send[i].HFReference = source->Send[i].HFReference;
+ props->Send[i].GainLF = source->Send[i].GainLF;
+ props->Send[i].LFReference = source->Send[i].LFReference;
}
- else if(state == AL_STOPPED)
+
+ /* Set the new container for updating internal parameters. */
+ props = ATOMIC_EXCHANGE_PTR(&voice->Update, props, almemory_order_acq_rel);
+ if(props)
{
- do_stop:
- if(Source->state != AL_INITIAL)
- {
- Source->state = AL_STOPPED;
- ATOMIC_STORE(&Source->current_buffer, NULL);
- }
- Source->Offset = -1.0;
+ /* If there was an unused update container, put it back in the
+ * freelist.
+ */
+ ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &context->FreeVoiceProps, props);
}
- else if(state == AL_INITIAL)
+}
+
+void UpdateAllSourceProps(ALCcontext *context)
+{
+ ALsizei num_sends = context->Device->NumAuxSends;
+ ALsizei pos;
+
+ for(pos = 0;pos < context->VoiceCount;pos++)
{
- if(Source->state != AL_INITIAL)
- {
- Source->state = AL_INITIAL;
- Source->position = 0;
- Source->position_fraction = 0;
- ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
- }
- Source->Offset = -1.0;
+ ALvoice *voice = context->Voices[pos];
+ ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
+ if(source && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel))
+ UpdateSourceProps(source, voice, num_sends, context);
}
- WriteUnlock(&Source->queue_lock);
}
+
/* GetSourceSampleOffset
*
* Gets the current read offset for the given Source, in 32.32 fixed-point
* samples. The offset is relative to the start of the queue (not the start of
* the current buffer).
*/
-ALint64 GetSourceSampleOffset(ALsource *Source)
+static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
{
- const ALbufferlistitem *BufferList;
+ ALCdevice *device = context->Device;
const ALbufferlistitem *Current;
ALuint64 readPos;
+ ALuint refcount;
+ ALvoice *voice;
+
+ do {
+ Current = NULL;
+ readPos = 0;
+ while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
+ althrd_yield();
+ *clocktime = GetDeviceClockTime(device);
+
+ voice = GetSourceVoice(Source, context);
+ if(voice)
+ {
+ Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
- ReadLock(&Source->queue_lock);
- if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
- {
- ReadUnlock(&Source->queue_lock);
- return 0;
- }
+ readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32;
+ readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) <<
+ (32-FRACTIONBITS);
+ }
+ ATOMIC_THREAD_FENCE(almemory_order_acquire);
+ } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
- /* NOTE: This is the offset into the *current* buffer, so add the length of
- * any played buffers */
- readPos = (ALuint64)Source->position << 32;
- readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
- BufferList = ATOMIC_LOAD(&Source->queue);
- Current = ATOMIC_LOAD(&Source->current_buffer);
- while(BufferList && BufferList != Current)
+ if(voice)
{
- if(BufferList->buffer)
- readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
- BufferList = BufferList->next;
+ const ALbufferlistitem *BufferList = Source->queue;
+ while(BufferList && BufferList != Current)
+ {
+ readPos += (ALuint64)BufferList->max_samples << 32;
+ BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
+ almemory_order_relaxed);
+ }
+ readPos = minu64(readPos, U64(0x7fffffffffffffff));
}
- ReadUnlock(&Source->queue_lock);
- return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
+ return (ALint64)readPos;
}
/* GetSourceSecOffset
@@ -2739,174 +3305,171 @@ ALint64 GetSourceSampleOffset(ALsource *Source)
* Gets the current read offset for the given Source, in seconds. The offset is
* relative to the start of the queue (not the start of the current buffer).
*/
-static ALdouble GetSourceSecOffset(ALsource *Source)
+static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
{
- const ALbufferlistitem *BufferList;
+ ALCdevice *device = context->Device;
const ALbufferlistitem *Current;
- const ALbuffer *Buffer = NULL;
ALuint64 readPos;
+ ALuint refcount;
+ ALdouble offset;
+ ALvoice *voice;
+
+ do {
+ Current = NULL;
+ readPos = 0;
+ while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
+ althrd_yield();
+ *clocktime = GetDeviceClockTime(device);
+
+ voice = GetSourceVoice(Source, context);
+ if(voice)
+ {
+ Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
- ReadLock(&Source->queue_lock);
- if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
- {
- ReadUnlock(&Source->queue_lock);
- return 0.0;
- }
+ readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) <<
+ FRACTIONBITS;
+ readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
+ }
+ ATOMIC_THREAD_FENCE(almemory_order_acquire);
+ } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
- /* NOTE: This is the offset into the *current* buffer, so add the length of
- * any played buffers */
- readPos = (ALuint64)Source->position << FRACTIONBITS;
- readPos |= (ALuint64)Source->position_fraction;
- BufferList = ATOMIC_LOAD(&Source->queue);
- Current = ATOMIC_LOAD(&Source->current_buffer);
- while(BufferList && BufferList != Current)
+ offset = 0.0;
+ if(voice)
{
- const ALbuffer *buffer = BufferList->buffer;
- if(buffer != NULL)
+ const ALbufferlistitem *BufferList = Source->queue;
+ const ALbuffer *BufferFmt = NULL;
+ while(BufferList && BufferList != Current)
{
- if(!Buffer) Buffer = buffer;
- readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
+ ALsizei i = 0;
+ while(!BufferFmt && i < BufferList->num_buffers)
+ BufferFmt = BufferList->buffers[i++];
+ readPos += (ALuint64)BufferList->max_samples << FRACTIONBITS;
+ BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
+ almemory_order_relaxed);
}
- BufferList = BufferList->next;
- }
- while(BufferList && !Buffer)
- {
- Buffer = BufferList->buffer;
- BufferList = BufferList->next;
+ while(BufferList && !BufferFmt)
+ {
+ ALsizei i = 0;
+ while(!BufferFmt && i < BufferList->num_buffers)
+ BufferFmt = BufferList->buffers[i++];
+ BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
+ almemory_order_relaxed);
+ }
+ assert(BufferFmt != NULL);
+
+ offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
+ (ALdouble)BufferFmt->Frequency;
}
- assert(Buffer != NULL);
- ReadUnlock(&Source->queue_lock);
- return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
+ return offset;
}
-/* GetSourceOffsets
+/* GetSourceOffset
*
- * Gets the current read and write offsets for the given Source, in the
- * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
- * the start of the queue (not the start of the current buffer).
+ * Gets the current read offset for the given Source, in the appropriate format
+ * (Bytes, Samples or Seconds). The offset is relative to the start of the
+ * queue (not the start of the current buffer).
*/
-static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
+static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
{
- const ALbufferlistitem *BufferList;
+ ALCdevice *device = context->Device;
const ALbufferlistitem *Current;
- const ALbuffer *Buffer = NULL;
- ALboolean readFin = AL_FALSE;
- ALuint readPos, readPosFrac, writePos;
- ALuint totalBufferLen;
-
- ReadLock(&Source->queue_lock);
- if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
- {
- offset[0] = 0.0;
- offset[1] = 0.0;
- ReadUnlock(&Source->queue_lock);
- return;
- }
+ ALuint readPos;
+ ALsizei readPosFrac;
+ ALuint refcount;
+ ALdouble offset;
+ ALvoice *voice;
+
+ do {
+ Current = NULL;
+ readPos = readPosFrac = 0;
+ while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
+ althrd_yield();
+ voice = GetSourceVoice(Source, context);
+ if(voice)
+ {
+ Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
- if(updateLen > 0.0 && updateLen < 0.015)
- updateLen = 0.015;
+ readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed);
+ readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
+ }
+ ATOMIC_THREAD_FENCE(almemory_order_acquire);
+ } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
- /* NOTE: This is the offset into the *current* buffer, so add the length of
- * any played buffers */
- totalBufferLen = 0;
- readPos = Source->position;
- readPosFrac = Source->position_fraction;
- BufferList = ATOMIC_LOAD(&Source->queue);
- Current = ATOMIC_LOAD(&Source->current_buffer);
- while(BufferList != NULL)
+ offset = 0.0;
+ if(voice)
{
- const ALbuffer *buffer;
- readFin = readFin || (BufferList == Current);
- if((buffer=BufferList->buffer) != NULL)
+ const ALbufferlistitem *BufferList = Source->queue;
+ const ALbuffer *BufferFmt = NULL;
+ ALboolean readFin = AL_FALSE;
+ ALuint totalBufferLen = 0;
+
+ while(BufferList != NULL)
{
- if(!Buffer) Buffer = buffer;
- totalBufferLen += buffer->SampleLen;
- if(!readFin) readPos += buffer->SampleLen;
+ ALsizei i = 0;
+ while(!BufferFmt && i < BufferList->num_buffers)
+ BufferFmt = BufferList->buffers[i++];
+
+ readFin |= (BufferList == Current);
+ totalBufferLen += BufferList->max_samples;
+ if(!readFin) readPos += BufferList->max_samples;
+
+ BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
+ almemory_order_relaxed);
}
- BufferList = BufferList->next;
- }
- assert(Buffer != NULL);
+ assert(BufferFmt != NULL);
- if(Source->state == AL_PLAYING)
- writePos = readPos + (ALuint)(updateLen*Buffer->Frequency + 0.5f);
- else
- writePos = readPos;
+ if(Source->Looping)
+ readPos %= totalBufferLen;
+ else
+ {
+ /* Wrap back to 0 */
+ if(readPos >= totalBufferLen)
+ readPos = readPosFrac = 0;
+ }
- if(Source->Looping)
- {
- readPos %= totalBufferLen;
- writePos %= totalBufferLen;
- }
- else
- {
- /* Wrap positions back to 0 */
- if(readPos >= totalBufferLen)
- readPos = readPosFrac = 0;
- if(writePos >= totalBufferLen)
- writePos = 0;
- }
+ offset = 0.0;
+ switch(name)
+ {
+ case AL_SEC_OFFSET:
+ offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency;
+ break;
- switch(name)
- {
- case AL_SEC_OFFSET:
- offset[0] = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
- offset[1] = (ALdouble)writePos/Buffer->Frequency;
- break;
+ case AL_SAMPLE_OFFSET:
+ offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
+ break;
- case AL_SAMPLE_OFFSET:
- case AL_SAMPLE_RW_OFFSETS_SOFT:
- offset[0] = readPos + (ALdouble)readPosFrac/FRACTIONONE;
- offset[1] = (ALdouble)writePos;
- break;
+ case AL_BYTE_OFFSET:
+ if(BufferFmt->OriginalType == UserFmtIMA4)
+ {
+ ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
+ ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
+ ALuint FrameBlockSize = BufferFmt->OriginalAlign;
- case AL_BYTE_OFFSET:
- case AL_BYTE_RW_OFFSETS_SOFT:
- if(Buffer->OriginalType == UserFmtIMA4)
- {
- ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
- ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
- ALuint FrameBlockSize = Buffer->OriginalAlign;
-
- /* Round down to nearest ADPCM block */
- offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
- if(Source->state != AL_PLAYING)
- offset[1] = offset[0];
- else
+ /* Round down to nearest ADPCM block */
+ offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
+ }
+ else if(BufferFmt->OriginalType == UserFmtMSADPCM)
{
- /* Round up to nearest ADPCM block */
- offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
- FrameBlockSize * BlockSize);
+ ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
+ ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
+ ALuint FrameBlockSize = BufferFmt->OriginalAlign;
+
+ /* Round down to nearest ADPCM block */
+ offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
}
- }
- else if(Buffer->OriginalType == UserFmtMSADPCM)
- {
- ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
- ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
- ALuint FrameBlockSize = Buffer->OriginalAlign;
-
- /* Round down to nearest ADPCM block */
- offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
- if(Source->state != AL_PLAYING)
- offset[1] = offset[0];
else
{
- /* Round up to nearest ADPCM block */
- offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
- FrameBlockSize * BlockSize);
+ ALuint FrameSize = FrameSizeFromFmt(BufferFmt->FmtChannels,
+ BufferFmt->FmtType);
+ offset = (ALdouble)(readPos * FrameSize);
}
- }
- else
- {
- ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
- offset[0] = (ALdouble)(readPos * FrameSize);
- offset[1] = (ALdouble)(writePos * FrameSize);
- }
- break;
+ break;
+ }
}
- ReadUnlock(&Source->queue_lock);
+ return offset;
}
@@ -2915,37 +3478,32 @@ static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset,
* Apply the stored playback offset to the Source. This function will update
* the number of buffers "played" given the stored offset.
*/
-ALboolean ApplyOffset(ALsource *Source)
+static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
{
ALbufferlistitem *BufferList;
- const ALbuffer *Buffer;
- ALuint bufferLen, totalBufferLen;
- ALuint offset=0, frac=0;
+ ALuint totalBufferLen;
+ ALuint offset = 0;
+ ALsizei frac = 0;
/* Get sample frame offset */
if(!GetSampleOffset(Source, &offset, &frac))
return AL_FALSE;
totalBufferLen = 0;
- BufferList = ATOMIC_LOAD(&Source->queue);
+ BufferList = Source->queue;
while(BufferList && totalBufferLen <= offset)
{
- Buffer = BufferList->buffer;
- bufferLen = Buffer ? Buffer->SampleLen : 0;
-
- if(bufferLen > offset-totalBufferLen)
+ if((ALuint)BufferList->max_samples > offset-totalBufferLen)
{
/* Offset is in this buffer */
- ATOMIC_STORE(&Source->current_buffer, BufferList);
-
- Source->position = offset - totalBufferLen;
- Source->position_fraction = frac;
+ ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release);
return AL_TRUE;
}
+ totalBufferLen += BufferList->max_samples;
- totalBufferLen += bufferLen;
-
- BufferList = BufferList->next;
+ BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
}
/* Offset is out of range of the queue */
@@ -2959,26 +3517,27 @@ ALboolean ApplyOffset(ALsource *Source)
* or Second offset supplied by the application). This takes into account the
* fact that the buffer format may have been modifed since.
*/
-static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
+static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac)
{
- const ALbuffer *Buffer = NULL;
+ const ALbuffer *BufferFmt = NULL;
const ALbufferlistitem *BufferList;
ALdouble dbloff, dblfrac;
/* Find the first valid Buffer in the Queue */
- BufferList = ATOMIC_LOAD(&Source->queue);
+ BufferList = Source->queue;
while(BufferList)
{
- if(BufferList->buffer)
- {
- Buffer = BufferList->buffer;
- break;
- }
- BufferList = BufferList->next;
+ ALsizei i;
+ for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++)
+ BufferFmt = BufferList->buffers[i];
+ if(BufferFmt) break;
+ BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
+ almemory_order_relaxed);
}
- if(!Buffer)
+ if(!BufferFmt)
{
- Source->Offset = -1.0;
+ Source->OffsetType = AL_NONE;
+ Source->Offset = 0.0;
return AL_FALSE;
}
@@ -2987,74 +3546,160 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
case AL_BYTE_OFFSET:
/* Determine the ByteOffset (and ensure it is block aligned) */
*offset = (ALuint)Source->Offset;
- if(Buffer->OriginalType == UserFmtIMA4)
+ if(BufferFmt->OriginalType == UserFmtIMA4)
{
- ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
- *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
- *offset *= Buffer->OriginalAlign;
+ ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
+ *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels);
+ *offset *= BufferFmt->OriginalAlign;
}
- else if(Buffer->OriginalType == UserFmtMSADPCM)
+ else if(BufferFmt->OriginalType == UserFmtMSADPCM)
{
- ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
- *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
- *offset *= Buffer->OriginalAlign;
+ ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
+ *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels);
+ *offset *= BufferFmt->OriginalAlign;
}
else
- *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
+ *offset /= FrameSizeFromFmt(BufferFmt->FmtChannels, BufferFmt->FmtType);
*frac = 0;
break;
case AL_SAMPLE_OFFSET:
dblfrac = modf(Source->Offset, &dbloff);
*offset = (ALuint)mind(dbloff, UINT_MAX);
- *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
+ *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
break;
case AL_SEC_OFFSET:
- dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
+ dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff);
*offset = (ALuint)mind(dbloff, UINT_MAX);
- *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
+ *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
break;
}
- Source->Offset = -1.0;
+ Source->OffsetType = AL_NONE;
+ Source->Offset = 0.0;
return AL_TRUE;
}
+static ALsource *AllocSource(ALCcontext *context)
+{
+ ALCdevice *device = context->Device;
+ SourceSubList *sublist, *subend;
+ ALsource *source = NULL;
+ ALsizei lidx = 0;
+ ALsizei slidx;
+
+ almtx_lock(&context->SourceLock);
+ if(context->NumSources >= device->SourcesMax)
+ {
+ almtx_unlock(&context->SourceLock);
+ alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax);
+ return NULL;
+ }
+ sublist = VECTOR_BEGIN(context->SourceList);
+ subend = VECTOR_END(context->SourceList);
+ for(;sublist != subend;++sublist)
+ {
+ if(sublist->FreeMask)
+ {
+ slidx = CTZ64(sublist->FreeMask);
+ source = sublist->Sources + slidx;
+ break;
+ }
+ ++lidx;
+ }
+ if(UNLIKELY(!source))
+ {
+ const SourceSubList empty_sublist = { 0, NULL };
+ /* Don't allocate so many list entries that the 32-bit ID could
+ * overflow...
+ */
+ if(UNLIKELY(VECTOR_SIZE(context->SourceList) >= 1<<25))
+ {
+ almtx_unlock(&device->BufferLock);
+ alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated");
+ return NULL;
+ }
+ lidx = (ALsizei)VECTOR_SIZE(context->SourceList);
+ VECTOR_PUSH_BACK(context->SourceList, empty_sublist);
+ sublist = &VECTOR_BACK(context->SourceList);
+ sublist->FreeMask = ~U64(0);
+ sublist->Sources = al_calloc(16, sizeof(ALsource)*64);
+ if(UNLIKELY(!sublist->Sources))
+ {
+ VECTOR_POP_BACK(context->SourceList);
+ almtx_unlock(&context->SourceLock);
+ alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch");
+ return NULL;
+ }
+
+ slidx = 0;
+ source = sublist->Sources + slidx;
+ }
+
+ memset(source, 0, sizeof(*source));
+ InitSourceParams(source, device->NumAuxSends);
+
+ /* Add 1 to avoid source ID 0. */
+ source->id = ((lidx<<6) | slidx) + 1;
+
+ context->NumSources++;
+ sublist->FreeMask &= ~(U64(1)<<slidx);
+ almtx_unlock(&context->SourceLock);
+
+ return source;
+}
+
+static void FreeSource(ALCcontext *context, ALsource *source)
+{
+ ALCdevice *device = context->Device;
+ ALuint id = source->id - 1;
+ ALsizei lidx = id >> 6;
+ ALsizei slidx = id & 0x3f;
+ ALvoice *voice;
+
+ ALCdevice_Lock(device);
+ if((voice=GetSourceVoice(source, context)) != NULL)
+ {
+ ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
+ }
+ ALCdevice_Unlock(device);
+
+ DeinitSource(source, device->NumAuxSends);
+ memset(source, 0, sizeof(*source));
+
+ VECTOR_ELEM(context->SourceList, lidx).FreeMask |= U64(1) << slidx;
+ context->NumSources--;
+}
+
/* ReleaseALSources
*
* Destroys all sources in the source map.
*/
-ALvoid ReleaseALSources(ALCcontext *Context)
+ALvoid ReleaseALSources(ALCcontext *context)
{
- ALbufferlistitem *item;
- ALsizei pos;
- ALuint j;
- for(pos = 0;pos < Context->SourceMap.size;pos++)
+ ALCdevice *device = context->Device;
+ SourceSubList *sublist = VECTOR_BEGIN(context->SourceList);
+ SourceSubList *subend = VECTOR_END(context->SourceList);
+ size_t leftover = 0;
+ for(;sublist != subend;++sublist)
{
- ALsource *temp = Context->SourceMap.array[pos].value;
- Context->SourceMap.array[pos].value = NULL;
-
- item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
- while(item != NULL)
+ ALuint64 usemask = ~sublist->FreeMask;
+ while(usemask)
{
- ALbufferlistitem *next = item->next;
- if(item->buffer != NULL)
- DecrementRef(&item->buffer->ref);
- free(item);
- item = next;
- }
+ ALsizei idx = CTZ64(usemask);
+ ALsource *source = sublist->Sources + idx;
- for(j = 0;j < MAX_SENDS;++j)
- {
- if(temp->Send[j].Slot)
- DecrementRef(&temp->Send[j].Slot->ref);
- temp->Send[j].Slot = NULL;
- }
+ DeinitSource(source, device->NumAuxSends);
+ memset(source, 0, sizeof(*source));
+ ++leftover;
- FreeThunkEntry(temp->id);
- memset(temp, 0, sizeof(*temp));
- al_free(temp);
+ usemask &= ~(U64(1) << idx);
+ }
+ sublist->FreeMask = ~usemask;
}
+ if(leftover > 0)
+ WARN("(%p) Deleted "SZFMT" Source%s\n", device, leftover, (leftover==1)?"":"s");
}
diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c
index dca41363..ce93e143 100644
--- a/OpenAL32/alState.c
+++ b/OpenAL32/alState.c
@@ -20,12 +20,15 @@
#include "config.h"
+#include "version.h"
+
#include <stdlib.h>
#include "alMain.h"
#include "AL/alc.h"
#include "AL/al.h"
#include "AL/alext.h"
#include "alError.h"
+#include "alListener.h"
#include "alSource.h"
#include "alAuxEffectSlot.h"
@@ -44,6 +47,31 @@ static const ALchar alErrInvalidValue[] = "Invalid Value";
static const ALchar alErrInvalidOp[] = "Invalid Operation";
static const ALchar alErrOutOfMemory[] = "Out of Memory";
+/* Resampler strings */
+static const ALchar alPointResampler[] = "Nearest";
+static const ALchar alLinearResampler[] = "Linear";
+static const ALchar alCubicResampler[] = "Cubic";
+static const ALchar alBSinc12Resampler[] = "11th order Sinc";
+static const ALchar alBSinc24Resampler[] = "23rd order Sinc";
+
+/* WARNING: Non-standard export! Not part of any extension, or exposed in the
+ * alcFunctions list.
+ */
+AL_API const ALchar* AL_APIENTRY alsoft_get_version(void)
+{
+ const char *spoof = getenv("ALSOFT_SPOOF_VERSION");
+ if(spoof && spoof[0] != '\0') return spoof;
+ return ALSOFT_VERSION;
+}
+
+#define DO_UPDATEPROPS() do { \
+ if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
+ UpdateContextProps(context); \
+ else \
+ ATOMIC_FLAG_CLEAR(&context->PropsClean, almemory_order_release); \
+} while(0)
+
+
AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
{
ALCcontext *context;
@@ -51,18 +79,19 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
context = GetContextRef();
if(!context) return;
+ almtx_lock(&context->PropLock);
switch(capability)
{
case AL_SOURCE_DISTANCE_MODEL:
context->SourceDistanceModel = AL_TRUE;
- ATOMIC_STORE(&context->UpdateSources, 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);
}
+ almtx_unlock(&context->PropLock);
-done:
ALCcontext_DecRef(context);
}
@@ -73,18 +102,19 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
context = GetContextRef();
if(!context) return;
+ almtx_lock(&context->PropLock);
switch(capability)
{
case AL_SOURCE_DISTANCE_MODEL:
context->SourceDistanceModel = AL_FALSE;
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
+ DO_UPDATEPROPS();
break;
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability);
}
+ almtx_unlock(&context->PropLock);
-done:
ALCcontext_DecRef(context);
}
@@ -96,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:
@@ -103,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;
}
@@ -120,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:
@@ -143,16 +174,30 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
- value = context->DeferUpdates;
+ if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
+ value = AL_TRUE;
+ break;
+
+ case AL_GAIN_LIMIT_SOFT:
+ if(GAIN_MIX_MAX/context->GainBoost != 0.0f)
+ value = AL_TRUE;
+ break;
+
+ case AL_NUM_RESAMPLERS_SOFT:
+ /* Always non-0. */
+ value = AL_TRUE;
+ break;
+
+ case AL_DEFAULT_RESAMPLER_SOFT:
+ value = ResamplerDefault ? AL_TRUE : AL_FALSE;
break;
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname);
}
+ almtx_unlock(&context->PropLock);
-done:
ALCcontext_DecRef(context);
-
return value;
}
@@ -164,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:
@@ -183,16 +229,28 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
- value = (ALdouble)context->DeferUpdates;
+ if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
+ value = (ALdouble)AL_TRUE;
+ break;
+
+ case AL_GAIN_LIMIT_SOFT:
+ value = (ALdouble)GAIN_MIX_MAX/context->GainBoost;
+ break;
+
+ case AL_NUM_RESAMPLERS_SOFT:
+ value = (ALdouble)(ResamplerMax + 1);
+ break;
+
+ case AL_DEFAULT_RESAMPLER_SOFT:
+ value = (ALdouble)ResamplerDefault;
break;
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_VALUE, "Invalid double property 0x%04x", pname);
}
+ almtx_unlock(&context->PropLock);
-done:
ALCcontext_DecRef(context);
-
return value;
}
@@ -204,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:
@@ -223,16 +282,28 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
- value = (ALfloat)context->DeferUpdates;
+ if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
+ value = (ALfloat)AL_TRUE;
+ break;
+
+ case AL_GAIN_LIMIT_SOFT:
+ value = GAIN_MIX_MAX/context->GainBoost;
+ break;
+
+ case AL_NUM_RESAMPLERS_SOFT:
+ value = (ALfloat)(ResamplerMax + 1);
+ break;
+
+ case AL_DEFAULT_RESAMPLER_SOFT:
+ value = (ALfloat)ResamplerDefault;
break;
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_VALUE, "Invalid float property 0x%04x", pname);
}
+ almtx_unlock(&context->PropLock);
-done:
ALCcontext_DecRef(context);
-
return value;
}
@@ -244,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:
@@ -263,16 +335,28 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
- value = (ALint)context->DeferUpdates;
+ if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
+ value = (ALint)AL_TRUE;
+ break;
+
+ case AL_GAIN_LIMIT_SOFT:
+ value = (ALint)(GAIN_MIX_MAX/context->GainBoost);
+ break;
+
+ case AL_NUM_RESAMPLERS_SOFT:
+ value = ResamplerMax + 1;
+ break;
+
+ case AL_DEFAULT_RESAMPLER_SOFT:
+ value = ResamplerDefault;
break;
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname);
}
+ almtx_unlock(&context->PropLock);
-done:
ALCcontext_DecRef(context);
-
return value;
}
@@ -284,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:
@@ -303,16 +388,56 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
- value = (ALint64SOFT)context->DeferUpdates;
+ if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
+ value = (ALint64SOFT)AL_TRUE;
+ break;
+
+ case AL_GAIN_LIMIT_SOFT:
+ value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost);
+ break;
+
+ case AL_NUM_RESAMPLERS_SOFT:
+ value = (ALint64SOFT)(ResamplerMax + 1);
+ break;
+
+ case AL_DEFAULT_RESAMPLER_SOFT:
+ value = (ALint64SOFT)ResamplerDefault;
break;
default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ alSetError(context, AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname);
}
+ almtx_unlock(&context->PropLock);
-done:
ALCcontext_DecRef(context);
+ return value;
+}
+
+AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname)
+{
+ ALCcontext *context;
+ void *value = NULL;
+ context = GetContextRef();
+ if(!context) return NULL;
+
+ almtx_lock(&context->PropLock);
+ switch(pname)
+ {
+ case AL_EVENT_CALLBACK_FUNCTION_SOFT:
+ value = context->EventCb;
+ break;
+
+ case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
+ value = context->EventParam;
+ break;
+
+ default:
+ alSetError(context, AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname);
+ }
+ almtx_unlock(&context->PropLock);
+
+ ALCcontext_DecRef(context);
return value;
}
@@ -329,6 +454,9 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
+ case AL_GAIN_LIMIT_SOFT:
+ case AL_NUM_RESAMPLERS_SOFT:
+ case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetBoolean(pname);
return;
}
@@ -337,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);
}
@@ -362,6 +489,9 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
+ case AL_GAIN_LIMIT_SOFT:
+ case AL_NUM_RESAMPLERS_SOFT:
+ case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetDouble(pname);
return;
}
@@ -370,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);
}
@@ -395,6 +524,9 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
+ case AL_GAIN_LIMIT_SOFT:
+ case AL_NUM_RESAMPLERS_SOFT:
+ case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetFloat(pname);
return;
}
@@ -403,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);
}
@@ -428,6 +559,9 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
+ case AL_GAIN_LIMIT_SOFT:
+ case AL_NUM_RESAMPLERS_SOFT:
+ case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetInteger(pname);
return;
}
@@ -436,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);
}
@@ -459,6 +594,9 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
+ case AL_GAIN_LIMIT_SOFT:
+ case AL_NUM_RESAMPLERS_SOFT:
+ case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetInteger64SOFT(pname);
return;
}
@@ -467,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);
}
@@ -528,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;
}
@@ -545,12 +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);
-
- context->DopplerFactor = value;
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
+ 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);
+ }
-done:
ALCcontext_DecRef(context);
}
@@ -561,13 +730,30 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
context = GetContextRef();
if(!context) return;
- if(!(value >= 0.0f && isfinite(value)))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ 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);
+ }
- context->DopplerVelocity = value;
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
+ if(!(value >= 0.0f && isfinite(value)))
+ 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);
+ }
-done:
ALCcontext_DecRef(context);
}
@@ -579,12 +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);
-
- context->SpeedOfSound = value;
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
+ 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);
+ }
-done:
ALCcontext_DecRef(context);
}
@@ -599,13 +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);
-
- context->DistanceModel = value;
- if(!context->SourceDistanceModel)
- ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
+ alSetError(context, AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
+ else
+ {
+ almtx_lock(&context->PropLock);
+ context->DistanceModel = value;
+ if(!context->SourceDistanceModel)
+ DO_UPDATEPROPS();
+ almtx_unlock(&context->PropLock);
+ }
-done:
ALCcontext_DecRef(context);
}
@@ -633,3 +825,76 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
ALCcontext_DecRef(context);
}
+
+
+AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
+{
+ const char *ResamplerNames[] = {
+ alPointResampler, alLinearResampler,
+ alCubicResampler, alBSinc12Resampler,
+ alBSinc24Resampler,
+ };
+ const ALchar *value = NULL;
+ ALCcontext *context;
+
+ static_assert(COUNTOF(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list");
+
+ context = GetContextRef();
+ if(!context) return NULL;
+
+ switch(pname)
+ {
+ case AL_RESAMPLER_NAME_SOFT:
+ if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames))
+ SETERR_GOTO(context, AL_INVALID_VALUE, done, "Resampler name index %d out of range",
+ index);
+ value = ResamplerNames[index];
+ break;
+
+ default:
+ alSetError(context, AL_INVALID_VALUE, "Invalid string indexed property");
+ }
+
+done:
+ ALCcontext_DecRef(context);
+ return value;
+}
+
+
+void UpdateContextProps(ALCcontext *context)
+{
+ struct ALcontextProps *props;
+
+ /* Get an unused proprty container, or allocate a new one as needed. */
+ props = ATOMIC_LOAD(&context->FreeContextProps, almemory_order_acquire);
+ if(!props)
+ props = al_calloc(16, sizeof(*props));
+ else
+ {
+ struct ALcontextProps *next;
+ do {
+ next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
+ } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeContextProps, &props, next,
+ almemory_order_seq_cst, almemory_order_acquire) == 0);
+ }
+
+ /* Copy in current property values. */
+ props->MetersPerUnit = context->MetersPerUnit;
+
+ props->DopplerFactor = context->DopplerFactor;
+ props->DopplerVelocity = context->DopplerVelocity;
+ props->SpeedOfSound = context->SpeedOfSound;
+
+ props->SourceDistanceModel = context->SourceDistanceModel;
+ props->DistanceModel = context->DistanceModel;
+
+ /* Set the new container for updating internal parameters. */
+ props = ATOMIC_EXCHANGE_PTR(&context->Update, props, almemory_order_acq_rel);
+ if(props)
+ {
+ /* If there was an unused update container, put it back in the
+ * freelist.
+ */
+ ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &context->FreeContextProps, props);
+ }
+}
diff --git a/OpenAL32/alThunk.c b/OpenAL32/alThunk.c
deleted file mode 100644
index 0cebad42..00000000
--- a/OpenAL32/alThunk.c
+++ /dev/null
@@ -1,103 +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"
-
-
-static ATOMIC(ALenum) *ThunkArray;
-static ALuint ThunkArraySize;
-static RWLock ThunkLock;
-
-void ThunkInit(void)
-{
- RWLockInit(&ThunkLock);
- ThunkArraySize = 1;
- ThunkArray = al_calloc(16, ThunkArraySize * sizeof(*ThunkArray));
-}
-
-void ThunkExit(void)
-{
- al_free(ThunkArray);
- ThunkArray = NULL;
- ThunkArraySize = 0;
-}
-
-ALenum NewThunkEntry(ALuint *index)
-{
- void *NewList;
- ALuint i;
-
- ReadLock(&ThunkLock);
- for(i = 0;i < ThunkArraySize;i++)
- {
- if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE)
- {
- ReadUnlock(&ThunkLock);
- *index = i+1;
- return AL_NO_ERROR;
- }
- }
- ReadUnlock(&ThunkLock);
-
- WriteLock(&ThunkLock);
- /* Double-check that there's still no free entries, in case another
- * invocation just came through and increased the size of the array.
- */
- for(;i < ThunkArraySize;i++)
- {
- if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE)
- {
- WriteUnlock(&ThunkLock);
- *index = i+1;
- return AL_NO_ERROR;
- }
- }
-
- NewList = al_calloc(16, ThunkArraySize*2 * sizeof(*ThunkArray));
- if(!NewList)
- {
- WriteUnlock(&ThunkLock);
- ERR("Realloc failed to increase to %u entries!\n", ThunkArraySize*2);
- return AL_OUT_OF_MEMORY;
- }
- memcpy(NewList, ThunkArray, ThunkArraySize*sizeof(*ThunkArray));
- al_free(ThunkArray);
- ThunkArray = NewList;
- ThunkArraySize *= 2;
-
- ATOMIC_STORE(&ThunkArray[i], AL_TRUE);
- WriteUnlock(&ThunkLock);
-
- *index = i+1;
- return AL_NO_ERROR;
-}
-
-void FreeThunkEntry(ALuint index)
-{
- ReadLock(&ThunkLock);
- if(index > 0 && index <= ThunkArraySize)
- ATOMIC_STORE(&ThunkArray[index-1], AL_FALSE);
- ReadUnlock(&ThunkLock);
-}
diff --git a/OpenAL32/event.c b/OpenAL32/event.c
new file mode 100644
index 00000000..4c9c0be2
--- /dev/null
+++ b/OpenAL32/event.c
@@ -0,0 +1,127 @@
+
+#include "config.h"
+
+#include "AL/alc.h"
+#include "AL/al.h"
+#include "AL/alext.h"
+#include "alMain.h"
+#include "alError.h"
+#include "alAuxEffectSlot.h"
+#include "ringbuffer.h"
+
+
+int EventThread(void *arg)
+{
+ ALCcontext *context = arg;
+ bool quitnow = false;
+
+ while(!quitnow)
+ {
+ ALbitfieldSOFT enabledevts;
+ AsyncEvent evt;
+
+ if(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) == 0)
+ {
+ alsem_wait(&context->EventSem);
+ continue;
+ }
+
+ almtx_lock(&context->EventCbLock);
+ do {
+ quitnow = evt.EnumType == EventType_KillThread;
+ if(quitnow) break;
+
+ if(evt.EnumType == EventType_ReleaseEffectState)
+ {
+ ALeffectState_DecRef(evt.u.EffectState);
+ continue;
+ }
+
+ enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire);
+ if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType)
+ context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param,
+ (ALsizei)strlen(evt.u.user.msg), evt.u.user.msg, context->EventParam
+ );
+ } while(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) != 0);
+ 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;
+ 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]);
+ }
+
+ if(enable)
+ {
+ enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed);
+ 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.
+ */
+ }
+ }
+ else
+ {
+ enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed);
+ while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts&~flags,
+ almemory_order_acq_rel, almemory_order_acquire) == 0)
+ {
+ }
+ /* Wait to ensure the event handler sees the changed flags before
+ * returning.
+ */
+ almtx_lock(&context->EventCbLock);
+ almtx_unlock(&context->EventCbLock);
+ }
+
+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);
+}
diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c
index a02b217e..4a85f74a 100644
--- a/OpenAL32/sample_cvt.c
+++ b/OpenAL32/sample_cvt.c
@@ -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,92 +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;
-typedef struct {
- ALbyte b[3];
-} ALbyte3;
-static_assert(sizeof(ALbyte3)==sizeof(ALbyte[3]), "ALbyte3 size is not 3");
-typedef struct {
- ALubyte b[3];
-} ALubyte3;
-static_assert(sizeof(ALubyte3)==sizeof(ALubyte[3]), "ALubyte3 size is not 3");
-
-static inline ALshort DecodeMuLaw(ALmulaw val)
-{ return muLawDecompressionTable[val]; }
-
-static ALmulaw EncodeMuLaw(ALshort val)
-{
- 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)
+static void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align)
{
- 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++)
{
@@ -257,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;
}
}
- }
-}
-static void EncodeIMA4Block(ALima4 *dst, const ALshort *src, ALint *sample, ALint *index, ALint numchans, ALsizei align)
-{
- ALsizei j,k,c;
-
- 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;
- }
-
- for(j = 1;j < align;j += 8)
- {
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;
- }
+ int nibble = code[c]&0xf;
+ code[c] >>= 4;
- diff = mini(step*2, diff);
- nibble |= (diff*8/step - 1) / 2;
+ sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8;
+ sample[c] = clampi(sample[c], -32768, 32767);
- 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);
- index[c] += IMA4Index_adjust[nibble];
- index[c] = clampi(index[c], 0, 88);
-
- if(!(k&1)) *dst = nibble;
- else *(dst++) |= nibble<<4;
- }
+ *(dst++) = sample[c];
}
}
}
-
-static void DecodeMSADPCMBlock(ALshort *dst, const ALmsadpcm *src, ALint numchans, ALsizei align)
+static void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align)
{
- ALubyte blockpred[MAX_INPUT_CHANNELS];
- ALint delta[MAX_INPUT_CHANNELS];
- ALshort samples[MAX_INPUT_CHANNELS][2];
- ALint i, j;
+ ALubyte blockpred[MAX_INPUT_CHANNELS] = { 0 };
+ ALint delta[MAX_INPUT_CHANNELS] = { 0 };
+ ALshort samples[MAX_INPUT_CHANNELS][2] = { { 0, 0 } };
+ ALint c, i;
- for(i = 0;i < numchans;i++)
+ for(c = 0;c < numchans;c++)
{
- blockpred[i] = *(src++);
- blockpred[i] = minu(blockpred[i], 6);
+ blockpred[c] = *(src++);
+ blockpred[c] = minu(blockpred[c], 6);
}
- 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;
+ delta[c] = *(src++);
+ delta[c] |= *(src++) << 8;
+ delta[c] = (delta[c]^0x8000) - 32768;
}
- for(i = 0;i < numchans;i++)
+ for(c = 0;c < numchans;c++)
{
- samples[i][0] = *(src++);
- samples[i][0] |= *(src++) << 8;
- samples[i][0] = (samples[i][0]^0x8000) - 0x8000;
+ 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++)
{
- 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). */
@@ -402,545 +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++;
- }
- }
- }
-}
-
-
-static inline ALint DecodeByte3(ALbyte3 val)
-{
- if(IS_LITTLE_ENDIAN)
- return (val.b[2]<<16) | (((ALubyte)val.b[1])<<8) | ((ALubyte)val.b[0]);
- return (val.b[0]<<16) | (((ALubyte)val.b[1])<<8) | ((ALubyte)val.b[2]);
-}
-
-static inline ALbyte3 EncodeByte3(ALint val)
-{
- if(IS_LITTLE_ENDIAN)
- {
- ALbyte3 ret = {{ val, val>>8, val>>16 }};
- return ret;
- }
- else
- {
- ALbyte3 ret = {{ val>>16, val>>8, val }};
- return ret;
- }
-}
-
-static inline ALint DecodeUByte3(ALubyte3 val)
-{
- if(IS_LITTLE_ENDIAN)
- return (val.b[2]<<16) | (val.b[1]<<8) | (val.b[0]);
- return (val.b[0]<<16) | (val.b[1]<<8) | val.b[2];
-}
-
-static inline ALubyte3 EncodeUByte3(ALint val)
-{
- if(IS_LITTLE_ENDIAN)
- {
- ALubyte3 ret = {{ val, val>>8, val>>16 }};
- return ret;
- }
- else
- {
- ALubyte3 ret = {{ val>>16, val>>8, val }};
- return ret;
- }
-}
-
-
-static inline ALbyte Conv_ALbyte_ALbyte(ALbyte val)
-{ return val; }
-static inline ALbyte Conv_ALbyte_ALubyte(ALubyte val)
-{ return val-128; }
-static inline ALbyte Conv_ALbyte_ALshort(ALshort val)
-{ return val>>8; }
-static inline ALbyte Conv_ALbyte_ALushort(ALushort val)
-{ return (val>>8)-128; }
-static inline ALbyte Conv_ALbyte_ALint(ALint val)
-{ return val>>24; }
-static inline ALbyte Conv_ALbyte_ALuint(ALuint val)
-{ return (val>>24)-128; }
-static inline ALbyte Conv_ALbyte_ALfloat(ALfloat val)
-{
- if(val > 1.0f) return 127;
- if(val < -1.0f) return -128;
- return (ALint)(val * 127.0f);
-}
-static inline ALbyte Conv_ALbyte_ALdouble(ALdouble val)
-{
- if(val > 1.0) return 127;
- if(val < -1.0) return -128;
- return (ALint)(val * 127.0);
-}
-static inline ALbyte Conv_ALbyte_ALmulaw(ALmulaw val)
-{ return Conv_ALbyte_ALshort(DecodeMuLaw(val)); }
-static inline ALbyte Conv_ALbyte_ALalaw(ALalaw val)
-{ return Conv_ALbyte_ALshort(DecodeALaw(val)); }
-static inline ALbyte Conv_ALbyte_ALbyte3(ALbyte3 val)
-{ return DecodeByte3(val)>>16; }
-static inline ALbyte Conv_ALbyte_ALubyte3(ALubyte3 val)
-{ return (DecodeUByte3(val)>>16)-128; }
-
-static inline ALubyte Conv_ALubyte_ALbyte(ALbyte val)
-{ return val+128; }
-static inline ALubyte Conv_ALubyte_ALubyte(ALubyte val)
-{ return val; }
-static inline ALubyte Conv_ALubyte_ALshort(ALshort val)
-{ return (val>>8)+128; }
-static inline ALubyte Conv_ALubyte_ALushort(ALushort val)
-{ return val>>8; }
-static inline ALubyte Conv_ALubyte_ALint(ALint val)
-{ return (val>>24)+128; }
-static inline ALubyte Conv_ALubyte_ALuint(ALuint val)
-{ return val>>24; }
-static inline ALubyte Conv_ALubyte_ALfloat(ALfloat val)
-{
- if(val > 1.0f) return 255;
- if(val < -1.0f) return 0;
- return (ALint)(val * 127.0f) + 128;
-}
-static inline ALubyte Conv_ALubyte_ALdouble(ALdouble val)
-{
- if(val > 1.0) return 255;
- if(val < -1.0) return 0;
- return (ALint)(val * 127.0) + 128;
-}
-static inline ALubyte Conv_ALubyte_ALmulaw(ALmulaw val)
-{ return Conv_ALubyte_ALshort(DecodeMuLaw(val)); }
-static inline ALubyte Conv_ALubyte_ALalaw(ALalaw val)
-{ return Conv_ALubyte_ALshort(DecodeALaw(val)); }
-static inline ALubyte Conv_ALubyte_ALbyte3(ALbyte3 val)
-{ return (DecodeByte3(val)>>16)+128; }
-static inline ALubyte Conv_ALubyte_ALubyte3(ALubyte3 val)
-{ return DecodeUByte3(val)>>16; }
-
-static inline ALshort Conv_ALshort_ALbyte(ALbyte val)
-{ return val<<8; }
-static inline ALshort Conv_ALshort_ALubyte(ALubyte val)
-{ return (val-128)<<8; }
-static inline ALshort Conv_ALshort_ALshort(ALshort val)
-{ return val; }
-static inline ALshort Conv_ALshort_ALushort(ALushort val)
-{ return val-32768; }
-static inline ALshort Conv_ALshort_ALint(ALint val)
-{ return val>>16; }
-static inline ALshort Conv_ALshort_ALuint(ALuint val)
-{ return (val>>16)-32768; }
-static inline ALshort Conv_ALshort_ALfloat(ALfloat val)
-{
- if(val > 1.0f) return 32767;
- if(val < -1.0f) return -32768;
- return (ALint)(val * 32767.0f);
-}
-static inline ALshort Conv_ALshort_ALdouble(ALdouble val)
-{
- if(val > 1.0) return 32767;
- if(val < -1.0) return -32768;
- return (ALint)(val * 32767.0);
-}
-static inline ALshort Conv_ALshort_ALmulaw(ALmulaw val)
-{ return Conv_ALshort_ALshort(DecodeMuLaw(val)); }
-static inline ALshort Conv_ALshort_ALalaw(ALalaw val)
-{ return Conv_ALshort_ALshort(DecodeALaw(val)); }
-static inline ALshort Conv_ALshort_ALbyte3(ALbyte3 val)
-{ return DecodeByte3(val)>>8; }
-static inline ALshort Conv_ALshort_ALubyte3(ALubyte3 val)
-{ return (DecodeUByte3(val)>>8)-32768; }
-
-static inline ALushort Conv_ALushort_ALbyte(ALbyte val)
-{ return (val+128)<<8; }
-static inline ALushort Conv_ALushort_ALubyte(ALubyte val)
-{ return val<<8; }
-static inline ALushort Conv_ALushort_ALshort(ALshort val)
-{ return val+32768; }
-static inline ALushort Conv_ALushort_ALushort(ALushort val)
-{ return val; }
-static inline ALushort Conv_ALushort_ALint(ALint val)
-{ return (val>>16)+32768; }
-static inline ALushort Conv_ALushort_ALuint(ALuint val)
-{ return val>>16; }
-static inline ALushort Conv_ALushort_ALfloat(ALfloat val)
-{
- if(val > 1.0f) return 65535;
- if(val < -1.0f) return 0;
- return (ALint)(val * 32767.0f) + 32768;
-}
-static inline ALushort Conv_ALushort_ALdouble(ALdouble val)
-{
- if(val > 1.0) return 65535;
- if(val < -1.0) return 0;
- return (ALint)(val * 32767.0) + 32768;
-}
-static inline ALushort Conv_ALushort_ALmulaw(ALmulaw val)
-{ return Conv_ALushort_ALshort(DecodeMuLaw(val)); }
-static inline ALushort Conv_ALushort_ALalaw(ALalaw val)
-{ return Conv_ALushort_ALshort(DecodeALaw(val)); }
-static inline ALushort Conv_ALushort_ALbyte3(ALbyte3 val)
-{ return (DecodeByte3(val)>>8)+32768; }
-static inline ALushort Conv_ALushort_ALubyte3(ALubyte3 val)
-{ return DecodeUByte3(val)>>8; }
-
-static inline ALint Conv_ALint_ALbyte(ALbyte val)
-{ return val<<24; }
-static inline ALint Conv_ALint_ALubyte(ALubyte val)
-{ return (val-128)<<24; }
-static inline ALint Conv_ALint_ALshort(ALshort val)
-{ return val<<16; }
-static inline ALint Conv_ALint_ALushort(ALushort val)
-{ return (val-32768)<<16; }
-static inline ALint Conv_ALint_ALint(ALint val)
-{ return val; }
-static inline ALint Conv_ALint_ALuint(ALuint val)
-{ return val-2147483648u; }
-static inline ALint Conv_ALint_ALfloat(ALfloat val)
-{
- if(val > 1.0f) return 2147483647;
- if(val < -1.0f) return -2147483647-1;
- return (ALint)(val*16777215.0f) << 7;
-}
-static inline ALint Conv_ALint_ALdouble(ALdouble val)
-{
- if(val > 1.0) return 2147483647;
- if(val < -1.0) return -2147483647-1;
- return (ALint)(val * 2147483647.0);
-}
-static inline ALint Conv_ALint_ALmulaw(ALmulaw val)
-{ return Conv_ALint_ALshort(DecodeMuLaw(val)); }
-static inline ALint Conv_ALint_ALalaw(ALalaw val)
-{ return Conv_ALint_ALshort(DecodeALaw(val)); }
-static inline ALint Conv_ALint_ALbyte3(ALbyte3 val)
-{ return DecodeByte3(val)<<8; }
-static inline ALint Conv_ALint_ALubyte3(ALubyte3 val)
-{ return (DecodeUByte3(val)-8388608)<<8; }
-
-static inline ALuint Conv_ALuint_ALbyte(ALbyte val)
-{ return (val+128)<<24; }
-static inline ALuint Conv_ALuint_ALubyte(ALubyte val)
-{ return val<<24; }
-static inline ALuint Conv_ALuint_ALshort(ALshort val)
-{ return (val+32768)<<16; }
-static inline ALuint Conv_ALuint_ALushort(ALushort val)
-{ return val<<16; }
-static inline ALuint Conv_ALuint_ALint(ALint val)
-{ return val+2147483648u; }
-static inline ALuint Conv_ALuint_ALuint(ALuint val)
-{ return val; }
-static inline ALuint Conv_ALuint_ALfloat(ALfloat val)
-{
- if(val > 1.0f) return 4294967295u;
- if(val < -1.0f) return 0;
- return ((ALint)(val*16777215.0f)<<7) + 2147483648u;
-}
-static inline ALuint Conv_ALuint_ALdouble(ALdouble val)
-{
- if(val > 1.0) return 4294967295u;
- if(val < -1.0) return 0;
- return (ALint)(val * 2147483647.0) + 2147483648u;
-}
-static inline ALuint Conv_ALuint_ALmulaw(ALmulaw val)
-{ return Conv_ALuint_ALshort(DecodeMuLaw(val)); }
-static inline ALuint Conv_ALuint_ALalaw(ALalaw val)
-{ return Conv_ALuint_ALshort(DecodeALaw(val)); }
-static inline ALuint Conv_ALuint_ALbyte3(ALbyte3 val)
-{ return (DecodeByte3(val)+8388608)<<8; }
-static inline ALuint Conv_ALuint_ALubyte3(ALubyte3 val)
-{ return DecodeUByte3(val)<<8; }
-
-static inline ALfloat Conv_ALfloat_ALbyte(ALbyte val)
-{ return val * (1.0f/127.0f); }
-static inline ALfloat Conv_ALfloat_ALubyte(ALubyte val)
-{ return (val-128) * (1.0f/127.0f); }
-static inline ALfloat Conv_ALfloat_ALshort(ALshort val)
-{ return val * (1.0f/32767.0f); }
-static inline ALfloat Conv_ALfloat_ALushort(ALushort val)
-{ return (val-32768) * (1.0f/32767.0f); }
-static inline ALfloat Conv_ALfloat_ALint(ALint val)
-{ return (ALfloat)(val>>7) * (1.0f/16777215.0f); }
-static inline ALfloat Conv_ALfloat_ALuint(ALuint val)
-{ return (ALfloat)((ALint)(val>>7)-16777216) * (1.0f/16777215.0f); }
-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 ALfloat Conv_ALfloat_ALmulaw(ALmulaw val)
-{ return Conv_ALfloat_ALshort(DecodeMuLaw(val)); }
-static inline ALfloat Conv_ALfloat_ALalaw(ALalaw val)
-{ return Conv_ALfloat_ALshort(DecodeALaw(val)); }
-static inline ALfloat Conv_ALfloat_ALbyte3(ALbyte3 val)
-{ return (ALfloat)(DecodeByte3(val) * (1.0/8388607.0)); }
-static inline ALfloat Conv_ALfloat_ALubyte3(ALubyte3 val)
-{ return (ALfloat)((DecodeUByte3(val)-8388608) * (1.0/8388607.0)); }
-
-static inline ALdouble Conv_ALdouble_ALbyte(ALbyte val)
-{ return val * (1.0/127.0); }
-static inline ALdouble Conv_ALdouble_ALubyte(ALubyte val)
-{ return (val-128) * (1.0/127.0); }
-static inline ALdouble Conv_ALdouble_ALshort(ALshort val)
-{ return val * (1.0/32767.0); }
-static inline ALdouble Conv_ALdouble_ALushort(ALushort val)
-{ return (val-32768) * (1.0/32767.0); }
-static inline ALdouble Conv_ALdouble_ALint(ALint val)
-{ return val * (1.0/2147483647.0); }
-static inline ALdouble Conv_ALdouble_ALuint(ALuint val)
-{ return (ALint)(val-2147483648u) * (1.0/2147483647.0); }
-static inline ALdouble Conv_ALdouble_ALfloat(ALfloat val)
-{ return (val==val) ? val : 0.0f; }
-static inline ALdouble Conv_ALdouble_ALdouble(ALdouble val)
-{ return (val==val) ? val : 0.0; }
-static inline ALdouble Conv_ALdouble_ALmulaw(ALmulaw val)
-{ return Conv_ALdouble_ALshort(DecodeMuLaw(val)); }
-static inline ALdouble Conv_ALdouble_ALalaw(ALalaw val)
-{ return Conv_ALdouble_ALshort(DecodeALaw(val)); }
-static inline ALdouble Conv_ALdouble_ALbyte3(ALbyte3 val)
-{ return DecodeByte3(val) * (1.0/8388607.0); }
-static inline ALdouble Conv_ALdouble_ALubyte3(ALubyte3 val)
-{ return (DecodeUByte3(val)-8388608) * (1.0/8388607.0); }
-
-#define DECL_TEMPLATE(T) \
-static inline ALmulaw Conv_ALmulaw_##T(T val) \
-{ return EncodeMuLaw(Conv_ALshort_##T(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)
-static inline ALmulaw Conv_ALmulaw_ALmulaw(ALmulaw val)
-{ return val; }
-DECL_TEMPLATE(ALalaw)
-DECL_TEMPLATE(ALbyte3)
-DECL_TEMPLATE(ALubyte3)
-
-#undef DECL_TEMPLATE
-
-#define DECL_TEMPLATE(T) \
-static inline ALalaw Conv_ALalaw_##T(T val) \
-{ return EncodeALaw(Conv_ALshort_##T(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)
-DECL_TEMPLATE(ALmulaw)
-static inline ALalaw Conv_ALalaw_ALalaw(ALalaw val)
-{ return val; }
-DECL_TEMPLATE(ALbyte3)
-DECL_TEMPLATE(ALubyte3)
-
-#undef DECL_TEMPLATE
-
-#define DECL_TEMPLATE(T) \
-static inline ALbyte3 Conv_ALbyte3_##T(T val) \
-{ return EncodeByte3(Conv_ALint_##T(val)>>8); }
-
-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)
-static inline ALbyte3 Conv_ALbyte3_ALbyte3(ALbyte3 val)
-{ return val; }
-DECL_TEMPLATE(ALubyte3)
-
-#undef DECL_TEMPLATE
-
-#define DECL_TEMPLATE(T) \
-static inline ALubyte3 Conv_ALubyte3_##T(T val) \
-{ return EncodeUByte3(Conv_ALuint_##T(val)>>8); }
-
-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(ALbyte3)
-static inline ALubyte3 Conv_ALubyte3_ALubyte3(ALubyte3 val)
-{ return val; }
-
-#undef DECL_TEMPLATE
-
-
-#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_TEMPLATE(T, ALbyte3) \
-DECL_TEMPLATE(T, ALubyte3)
-
-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)
-DECL_TEMPLATE2(ALbyte3)
-DECL_TEMPLATE2(ALubyte3)
-
-#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)
@@ -950,103 +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)
-DECL_TEMPLATE(ALbyte3)
-DECL_TEMPLATE(ALubyte3)
-#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)
-DECL_TEMPLATE(ALbyte3)
-DECL_TEMPLATE(ALubyte3)
-
-#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)
@@ -1056,214 +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)
-DECL_TEMPLATE(ALbyte3)
-DECL_TEMPLATE(ALubyte3)
-
-#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)
-DECL_TEMPLATE(ALbyte3)
-DECL_TEMPLATE(ALubyte3)
-
-#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; \
- case UserFmtByte3: \
- Convert_##T##_ALbyte3(dst, src, numchans, len, align); \
- break; \
- case UserFmtUByte3: \
- Convert_##T##_ALubyte3(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)
-DECL_TEMPLATE(ALbyte3)
-DECL_TEMPLATE(ALubyte3)
-
-#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;
- case UserFmtByte3:
- Convert_ALbyte3(dst, src, srcType, numchans, len, align);
- break;
- case UserFmtUByte3:
- Convert_ALubyte3(dst, src, srcType, numchans, len, align);
- break;
- }
-}