aboutsummaryrefslogtreecommitdiffstats
path: root/OpenAL32/Include
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2019-04-07 23:39:04 +0200
committerSven Gothel <[email protected]>2019-04-07 23:39:04 +0200
commit73233ce69919fc19c53ce8663c5b8cc05227f07e (patch)
treef2b6ccc1a14d7c387f33398a44ea4511d7ecb212 /OpenAL32/Include
parent8efa4c7ba5ee8eb399d31a9884e45f743d4625ad (diff)
parent99a55c445211fea77af6ab61cbc6a6ec4fbdc9b9 (diff)
Merge branch 'v1.19' of git://repo.or.cz/openal-soft into v1.19v1.19
Diffstat (limited to 'OpenAL32/Include')
-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
12 files changed, 1287 insertions, 937 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 */