mirror of
https://github.com/love2d/megasource.git
synced 2026-08-20 04:30:45 +02:00
Update OpenAL Soft to commit 414b56edec5441211dc924fef365c54267c04f1c
This commit is contained in:
@@ -29,16 +29,21 @@ struct ALeffectStateVtable {
|
||||
void (*const Destruct)(ALeffectState *state);
|
||||
|
||||
ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
|
||||
void (*const update)(ALeffectState *state, const ALCdevice *device, const struct ALeffectslot *slot, const union ALeffectProps *props);
|
||||
void (*const update)(ALeffectState *state, const ALCcontext *context, const struct ALeffectslot *slot, const union ALeffectProps *props);
|
||||
void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei numChannels);
|
||||
|
||||
void (*const Delete)(void *ptr);
|
||||
};
|
||||
|
||||
/* Small hack to use a pointer-to-array types as a normal argument type.
|
||||
* Shouldn't be used directly.
|
||||
*/
|
||||
typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
|
||||
|
||||
#define DEFINE_ALEFFECTSTATE_VTABLE(T) \
|
||||
DECLARE_THUNK(T, ALeffectState, void, Destruct) \
|
||||
DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \
|
||||
DECLARE_THUNK3(T, ALeffectState, void, update, const ALCdevice*, const ALeffectslot*, const ALeffectProps*) \
|
||||
DECLARE_THUNK3(T, ALeffectState, void, update, const ALCcontext*, const ALeffectslot*, const ALeffectProps*) \
|
||||
DECLARE_THUNK4(T, ALeffectState, void, process, ALsizei, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALsizei) \
|
||||
static void T##_ALeffectState_Delete(void *ptr) \
|
||||
{ return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \
|
||||
@@ -54,21 +59,22 @@ static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \
|
||||
}
|
||||
|
||||
|
||||
struct ALeffectStateFactoryVtable;
|
||||
struct EffectStateFactoryVtable;
|
||||
|
||||
typedef struct ALeffectStateFactory {
|
||||
const struct ALeffectStateFactoryVtable *vtbl;
|
||||
} ALeffectStateFactory;
|
||||
typedef struct EffectStateFactory {
|
||||
const struct EffectStateFactoryVtable *vtab;
|
||||
} EffectStateFactory;
|
||||
|
||||
struct ALeffectStateFactoryVtable {
|
||||
ALeffectState *(*const create)(ALeffectStateFactory *factory);
|
||||
struct EffectStateFactoryVtable {
|
||||
ALeffectState *(*const create)(EffectStateFactory *factory);
|
||||
};
|
||||
#define EffectStateFactory_create(x) ((x)->vtab->create((x)))
|
||||
|
||||
#define DEFINE_ALEFFECTSTATEFACTORY_VTABLE(T) \
|
||||
DECLARE_THUNK(T, ALeffectStateFactory, ALeffectState*, create) \
|
||||
#define DEFINE_EFFECTSTATEFACTORY_VTABLE(T) \
|
||||
DECLARE_THUNK(T, EffectStateFactory, ALeffectState*, create) \
|
||||
\
|
||||
static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = { \
|
||||
T##_ALeffectStateFactory_create, \
|
||||
static const struct EffectStateFactoryVtable T##_EffectStateFactory_vtable = { \
|
||||
T##_EffectStateFactory_create, \
|
||||
}
|
||||
|
||||
|
||||
@@ -110,17 +116,18 @@ typedef struct ALeffectslot {
|
||||
RefCount ref;
|
||||
|
||||
ATOMIC(struct ALeffectslotProps*) Update;
|
||||
ATOMIC(struct ALeffectslotProps*) FreeList;
|
||||
|
||||
struct {
|
||||
ALfloat Gain;
|
||||
ALboolean AuxSendAuto;
|
||||
|
||||
ALenum EffectType;
|
||||
ALeffectProps EffectProps;
|
||||
ALeffectState *EffectState;
|
||||
|
||||
ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */
|
||||
ALfloat DecayTime;
|
||||
ALfloat DecayLFRatio;
|
||||
ALfloat DecayHFRatio;
|
||||
ALboolean DecayHFLimit;
|
||||
ALfloat AirAbsorptionGainHF;
|
||||
@@ -133,9 +140,9 @@ typedef struct ALeffectslot {
|
||||
BFChannelConfig ChanMap[MAX_EFFECT_CHANNELS];
|
||||
/* Wet buffer configuration is ACN channel order with N3D scaling:
|
||||
* * Channel 0 is the unattenuated mono signal.
|
||||
* * Channel 1 is OpenAL -X
|
||||
* * Channel 2 is OpenAL Y
|
||||
* * Channel 3 is OpenAL -Z
|
||||
* * Channel 1 is OpenAL -X * sqrt(3)
|
||||
* * Channel 2 is OpenAL Y * sqrt(3)
|
||||
* * Channel 3 is OpenAL -Z * sqrt(3)
|
||||
* Consequently, effects that only want to work with mono input can use
|
||||
* channel 0 by itself. Effects that want multichannel can process the
|
||||
* ambisonics signal and make a B-Format pan (ComputeFirstOrderGains) for
|
||||
@@ -144,44 +151,30 @@ typedef struct ALeffectslot {
|
||||
alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE];
|
||||
} ALeffectslot;
|
||||
|
||||
inline void LockEffectSlotsRead(ALCcontext *context)
|
||||
{ LockUIntMapRead(&context->EffectSlotMap); }
|
||||
inline void UnlockEffectSlotsRead(ALCcontext *context)
|
||||
{ UnlockUIntMapRead(&context->EffectSlotMap); }
|
||||
inline void LockEffectSlotsWrite(ALCcontext *context)
|
||||
{ LockUIntMapWrite(&context->EffectSlotMap); }
|
||||
inline void UnlockEffectSlotsWrite(ALCcontext *context)
|
||||
{ UnlockUIntMapWrite(&context->EffectSlotMap); }
|
||||
|
||||
inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
|
||||
{ return (struct ALeffectslot*)LookupUIntMapKeyNoLock(&context->EffectSlotMap, id); }
|
||||
inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id)
|
||||
{ return (struct ALeffectslot*)RemoveUIntMapKeyNoLock(&context->EffectSlotMap, id); }
|
||||
|
||||
ALenum InitEffectSlot(ALeffectslot *slot);
|
||||
void DeinitEffectSlot(ALeffectslot *slot);
|
||||
void UpdateEffectSlotProps(ALeffectslot *slot);
|
||||
void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context);
|
||||
void UpdateAllEffectSlotProps(ALCcontext *context);
|
||||
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
|
||||
|
||||
|
||||
ALeffectStateFactory *ALnullStateFactory_getFactory(void);
|
||||
ALeffectStateFactory *ALreverbStateFactory_getFactory(void);
|
||||
ALeffectStateFactory *ALchorusStateFactory_getFactory(void);
|
||||
ALeffectStateFactory *ALcompressorStateFactory_getFactory(void);
|
||||
ALeffectStateFactory *ALdistortionStateFactory_getFactory(void);
|
||||
ALeffectStateFactory *ALechoStateFactory_getFactory(void);
|
||||
ALeffectStateFactory *ALequalizerStateFactory_getFactory(void);
|
||||
ALeffectStateFactory *ALflangerStateFactory_getFactory(void);
|
||||
ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void);
|
||||
EffectStateFactory *NullStateFactory_getFactory(void);
|
||||
EffectStateFactory *ReverbStateFactory_getFactory(void);
|
||||
EffectStateFactory *ChorusStateFactory_getFactory(void);
|
||||
EffectStateFactory *CompressorStateFactory_getFactory(void);
|
||||
EffectStateFactory *DistortionStateFactory_getFactory(void);
|
||||
EffectStateFactory *EchoStateFactory_getFactory(void);
|
||||
EffectStateFactory *EqualizerStateFactory_getFactory(void);
|
||||
EffectStateFactory *FlangerStateFactory_getFactory(void);
|
||||
EffectStateFactory *ModulatorStateFactory_getFactory(void);
|
||||
EffectStateFactory *PshifterStateFactory_getFactory(void);
|
||||
|
||||
ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void);
|
||||
EffectStateFactory *DedicatedStateFactory_getFactory(void);
|
||||
|
||||
|
||||
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect);
|
||||
ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
|
||||
|
||||
void InitEffectFactoryMap(void);
|
||||
void DeinitEffectFactoryMap(void);
|
||||
void ALeffectState_DecRef(ALeffectState *state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
#ifndef _AL_BUFFER_H_
|
||||
#define _AL_BUFFER_H_
|
||||
|
||||
#include "alMain.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/al.h"
|
||||
#include "AL/alext.h"
|
||||
|
||||
#include "inprogext.h"
|
||||
#include "atomic.h"
|
||||
#include "rwlock.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -9,29 +15,25 @@ extern "C" {
|
||||
|
||||
/* User formats */
|
||||
enum UserFmtType {
|
||||
UserFmtByte = AL_BYTE_SOFT,
|
||||
UserFmtUByte = AL_UNSIGNED_BYTE_SOFT,
|
||||
UserFmtShort = AL_SHORT_SOFT,
|
||||
UserFmtUShort = AL_UNSIGNED_SHORT_SOFT,
|
||||
UserFmtInt = AL_INT_SOFT,
|
||||
UserFmtUInt = AL_UNSIGNED_INT_SOFT,
|
||||
UserFmtFloat = AL_FLOAT_SOFT,
|
||||
UserFmtDouble = AL_DOUBLE_SOFT,
|
||||
UserFmtMulaw = AL_MULAW_SOFT,
|
||||
UserFmtAlaw = 0x10000000,
|
||||
UserFmtUByte,
|
||||
UserFmtShort,
|
||||
UserFmtFloat,
|
||||
UserFmtDouble,
|
||||
UserFmtMulaw,
|
||||
UserFmtAlaw,
|
||||
UserFmtIMA4,
|
||||
UserFmtMSADPCM,
|
||||
};
|
||||
enum UserFmtChannels {
|
||||
UserFmtMono = AL_MONO_SOFT,
|
||||
UserFmtStereo = AL_STEREO_SOFT,
|
||||
UserFmtRear = AL_REAR_SOFT,
|
||||
UserFmtQuad = AL_QUAD_SOFT,
|
||||
UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */
|
||||
UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */
|
||||
UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */
|
||||
UserFmtBFormat2D = AL_BFORMAT2D_SOFT, /* WXY */
|
||||
UserFmtBFormat3D = AL_BFORMAT3D_SOFT, /* WXYZ */
|
||||
UserFmtMono,
|
||||
UserFmtStereo,
|
||||
UserFmtRear,
|
||||
UserFmtQuad,
|
||||
UserFmtX51, /* (WFX order) */
|
||||
UserFmtX61, /* (WFX order) */
|
||||
UserFmtX71, /* (WFX order) */
|
||||
UserFmtBFormat2D, /* WXY */
|
||||
UserFmtBFormat3D, /* WXYZ */
|
||||
};
|
||||
|
||||
ALsizei BytesFromUserFmt(enum UserFmtType type);
|
||||
@@ -44,9 +46,12 @@ inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType
|
||||
|
||||
/* Storable formats */
|
||||
enum FmtType {
|
||||
FmtByte = UserFmtByte,
|
||||
FmtShort = UserFmtShort,
|
||||
FmtFloat = UserFmtFloat,
|
||||
FmtUByte = UserFmtUByte,
|
||||
FmtShort = UserFmtShort,
|
||||
FmtFloat = UserFmtFloat,
|
||||
FmtDouble = UserFmtDouble,
|
||||
FmtMulaw = UserFmtMulaw,
|
||||
FmtAlaw = UserFmtAlaw,
|
||||
};
|
||||
enum FmtChannels {
|
||||
FmtMono = UserFmtMono,
|
||||
@@ -72,18 +77,17 @@ inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
|
||||
typedef struct ALbuffer {
|
||||
ALvoid *data;
|
||||
|
||||
ALsizei Frequency;
|
||||
ALenum Format;
|
||||
ALsizei SampleLen;
|
||||
ALsizei Frequency;
|
||||
ALbitfieldSOFT Access;
|
||||
ALsizei SampleLen;
|
||||
|
||||
enum FmtChannels FmtChannels;
|
||||
enum FmtType FmtType;
|
||||
ALuint BytesAlloc;
|
||||
ALsizei BytesAlloc;
|
||||
|
||||
enum UserFmtChannels OriginalChannels;
|
||||
enum UserFmtType OriginalType;
|
||||
ALsizei OriginalSize;
|
||||
ALsizei OriginalAlign;
|
||||
enum UserFmtType OriginalType;
|
||||
ALsizei OriginalSize;
|
||||
ALsizei OriginalAlign;
|
||||
|
||||
ALsizei LoopStart;
|
||||
ALsizei LoopEnd;
|
||||
@@ -91,34 +95,17 @@ typedef struct ALbuffer {
|
||||
ATOMIC(ALsizei) UnpackAlign;
|
||||
ATOMIC(ALsizei) PackAlign;
|
||||
|
||||
ALbitfieldSOFT MappedAccess;
|
||||
ALsizei MappedOffset;
|
||||
ALsizei MappedSize;
|
||||
|
||||
/* Number of times buffer was attached to a source (deletion can only occur when 0) */
|
||||
RefCount ref;
|
||||
|
||||
RWLock lock;
|
||||
|
||||
/* Self ID */
|
||||
ALuint id;
|
||||
} ALbuffer;
|
||||
|
||||
ALbuffer *NewBuffer(ALCcontext *context);
|
||||
void DeleteBuffer(ALCdevice *device, ALbuffer *buffer);
|
||||
|
||||
ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc);
|
||||
|
||||
inline void LockBuffersRead(ALCdevice *device)
|
||||
{ LockUIntMapRead(&device->BufferMap); }
|
||||
inline void UnlockBuffersRead(ALCdevice *device)
|
||||
{ UnlockUIntMapRead(&device->BufferMap); }
|
||||
inline void LockBuffersWrite(ALCdevice *device)
|
||||
{ LockUIntMapWrite(&device->BufferMap); }
|
||||
inline void UnlockBuffersWrite(ALCdevice *device)
|
||||
{ UnlockUIntMapWrite(&device->BufferMap); }
|
||||
|
||||
inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
|
||||
{ return (struct ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); }
|
||||
inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id)
|
||||
{ return (struct ALbuffer*)RemoveUIntMapKeyNoLock(&device->BufferMap, id); }
|
||||
|
||||
ALvoid ReleaseALBuffers(ALCdevice *device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -10,23 +10,32 @@ extern "C" {
|
||||
struct ALeffect;
|
||||
|
||||
enum {
|
||||
AL__EAXREVERB = 0,
|
||||
AL__REVERB,
|
||||
AL__CHORUS,
|
||||
AL__COMPRESSOR,
|
||||
AL__DISTORTION,
|
||||
AL__ECHO,
|
||||
AL__EQUALIZER,
|
||||
AL__FLANGER,
|
||||
AL__MODULATOR,
|
||||
AL__DEDICATED,
|
||||
EAXREVERB_EFFECT = 0,
|
||||
REVERB_EFFECT,
|
||||
CHORUS_EFFECT,
|
||||
COMPRESSOR_EFFECT,
|
||||
DISTORTION_EFFECT,
|
||||
ECHO_EFFECT,
|
||||
EQUALIZER_EFFECT,
|
||||
FLANGER_EFFECT,
|
||||
MODULATOR_EFFECT,
|
||||
PSHIFTER_EFFECT,
|
||||
DEDICATED_EFFECT,
|
||||
|
||||
MAX_EFFECTS
|
||||
};
|
||||
extern ALboolean DisabledEffects[MAX_EFFECTS];
|
||||
|
||||
extern ALfloat ReverbBoost;
|
||||
extern ALboolean EmulateEAXReverb;
|
||||
|
||||
struct EffectList {
|
||||
const char name[16];
|
||||
int type;
|
||||
ALenum val;
|
||||
};
|
||||
#define EFFECTLIST_SIZE 12
|
||||
extern const struct EffectList EffectList[EFFECTLIST_SIZE];
|
||||
|
||||
|
||||
struct ALeffectVtable {
|
||||
void (*const setParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val);
|
||||
@@ -58,6 +67,7 @@ extern const struct ALeffectVtable ALequalizer_vtable;
|
||||
extern const struct ALeffectVtable ALflanger_vtable;
|
||||
extern const struct ALeffectVtable ALmodulator_vtable;
|
||||
extern const struct ALeffectVtable ALnull_vtable;
|
||||
extern const struct ALeffectVtable ALpshifter_vtable;
|
||||
extern const struct ALeffectVtable ALdedicated_vtable;
|
||||
|
||||
|
||||
@@ -98,7 +108,7 @@ typedef union ALeffectProps {
|
||||
ALfloat Depth;
|
||||
ALfloat Feedback;
|
||||
ALfloat Delay;
|
||||
} Chorus;
|
||||
} Chorus; /* Also Flanger */
|
||||
|
||||
struct {
|
||||
ALboolean OnOff;
|
||||
@@ -135,21 +145,17 @@ typedef union ALeffectProps {
|
||||
ALfloat HighGain;
|
||||
} Equalizer;
|
||||
|
||||
struct {
|
||||
ALint Waveform;
|
||||
ALint Phase;
|
||||
ALfloat Rate;
|
||||
ALfloat Depth;
|
||||
ALfloat Feedback;
|
||||
ALfloat Delay;
|
||||
} Flanger;
|
||||
|
||||
struct {
|
||||
ALfloat Frequency;
|
||||
ALfloat HighPassCutoff;
|
||||
ALint Waveform;
|
||||
} Modulator;
|
||||
|
||||
struct {
|
||||
ALint CoarseTune;
|
||||
ALint FineTune;
|
||||
} Pshifter;
|
||||
|
||||
struct {
|
||||
ALfloat Gain;
|
||||
} Dedicated;
|
||||
@@ -161,33 +167,27 @@ typedef struct ALeffect {
|
||||
|
||||
ALeffectProps Props;
|
||||
|
||||
const struct ALeffectVtable *vtbl;
|
||||
const struct ALeffectVtable *vtab;
|
||||
|
||||
/* Self ID */
|
||||
ALuint id;
|
||||
} ALeffect;
|
||||
|
||||
inline void LockEffectsRead(ALCdevice *device)
|
||||
{ LockUIntMapRead(&device->EffectMap); }
|
||||
inline void UnlockEffectsRead(ALCdevice *device)
|
||||
{ UnlockUIntMapRead(&device->EffectMap); }
|
||||
inline void LockEffectsWrite(ALCdevice *device)
|
||||
{ LockUIntMapWrite(&device->EffectMap); }
|
||||
inline void UnlockEffectsWrite(ALCdevice *device)
|
||||
{ UnlockUIntMapWrite(&device->EffectMap); }
|
||||
|
||||
inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id)
|
||||
{ return (struct ALeffect*)LookupUIntMapKeyNoLock(&device->EffectMap, id); }
|
||||
inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id)
|
||||
{ return (struct ALeffect*)RemoveUIntMapKeyNoLock(&device->EffectMap, id); }
|
||||
#define ALeffect_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v))
|
||||
#define ALeffect_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v))
|
||||
#define ALeffect_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v))
|
||||
#define ALeffect_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v))
|
||||
#define ALeffect_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v))
|
||||
#define ALeffect_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v))
|
||||
#define ALeffect_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v))
|
||||
#define ALeffect_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v))
|
||||
|
||||
inline ALboolean IsReverbEffect(ALenum type)
|
||||
{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; }
|
||||
|
||||
ALenum InitEffect(ALeffect *effect);
|
||||
ALvoid ReleaseALEffects(ALCdevice *device);
|
||||
void InitEffect(ALeffect *effect);
|
||||
void ReleaseALEffects(ALCdevice *device);
|
||||
|
||||
ALvoid LoadReverbPreset(const char *name, ALeffect *effect);
|
||||
void LoadReverbPreset(const char *name, ALeffect *effect);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _AL_ERROR_H_
|
||||
|
||||
#include "alMain.h"
|
||||
#include "logging.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -9,23 +10,18 @@ extern "C" {
|
||||
|
||||
extern ALboolean TrapALError;
|
||||
|
||||
ALvoid alSetError(ALCcontext *Context, ALenum errorCode);
|
||||
void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4);
|
||||
|
||||
#define SET_ERROR_AND_RETURN(ctx, err) do { \
|
||||
alSetError((ctx), (err)); \
|
||||
return; \
|
||||
} while(0)
|
||||
|
||||
#define SET_ERROR_AND_RETURN_VALUE(ctx, err, val) do { \
|
||||
alSetError((ctx), (err)); \
|
||||
return (val); \
|
||||
} while(0)
|
||||
|
||||
#define SET_ERROR_AND_GOTO(ctx, err, lbl) do { \
|
||||
alSetError((ctx), (err)); \
|
||||
#define SETERR_GOTO(ctx, err, lbl, ...) do { \
|
||||
alSetError((ctx), (err), __VA_ARGS__); \
|
||||
goto lbl; \
|
||||
} while(0)
|
||||
|
||||
#define SETERR_RETURN(ctx, err, retval, ...) do { \
|
||||
alSetError((ctx), (err), __VA_ARGS__); \
|
||||
return retval; \
|
||||
} while(0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#ifndef _AL_FILTER_H_
|
||||
#define _AL_FILTER_H_
|
||||
|
||||
#include "alMain.h"
|
||||
|
||||
#include "math_defs.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/al.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -13,99 +12,27 @@ extern "C" {
|
||||
#define HIGHPASSFREQREF (250.0f)
|
||||
|
||||
|
||||
/* Filters implementation is based on the "Cookbook formulae for audio
|
||||
* EQ biquad filter coefficients" by Robert Bristow-Johnson
|
||||
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
|
||||
*/
|
||||
/* Implementation note: For the shelf filters, the specified gain is for the
|
||||
* reference frequency, which is the centerpoint of the transition band. This
|
||||
* better matches EFX filter design. To set the gain for the shelf itself, use
|
||||
* the square root of the desired linear gain (or halve the dB gain).
|
||||
*/
|
||||
struct ALfilter;
|
||||
|
||||
typedef enum ALfilterType {
|
||||
/** EFX-style low-pass filter, specifying a gain and reference frequency. */
|
||||
ALfilterType_HighShelf,
|
||||
/** EFX-style high-pass filter, specifying a gain and reference frequency. */
|
||||
ALfilterType_LowShelf,
|
||||
/** Peaking filter, specifying a gain and reference frequency. */
|
||||
ALfilterType_Peaking,
|
||||
typedef struct ALfilterVtable {
|
||||
void (*const setParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val);
|
||||
void (*const setParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals);
|
||||
void (*const setParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val);
|
||||
void (*const setParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals);
|
||||
|
||||
/** Low-pass cut-off filter, specifying a cut-off frequency. */
|
||||
ALfilterType_LowPass,
|
||||
/** High-pass cut-off filter, specifying a cut-off frequency. */
|
||||
ALfilterType_HighPass,
|
||||
/** Band-pass filter, specifying a center frequency. */
|
||||
ALfilterType_BandPass,
|
||||
} ALfilterType;
|
||||
void (*const getParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val);
|
||||
void (*const getParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals);
|
||||
void (*const getParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val);
|
||||
void (*const getParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals);
|
||||
} ALfilterVtable;
|
||||
|
||||
typedef struct ALfilterState {
|
||||
ALfloat x[2]; /* History of two last input samples */
|
||||
ALfloat y[2]; /* History of two last output samples */
|
||||
ALfloat b0, b1, b2; /* Transfer function coefficients "b" */
|
||||
ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */
|
||||
} ALfilterState;
|
||||
/* Currently only a C-based filter process method is implemented. */
|
||||
#define ALfilterState_process ALfilterState_processC
|
||||
|
||||
/* Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the
|
||||
* reference gain and shelf slope parameter.
|
||||
* 0 < gain
|
||||
* 0 < slope <= 1
|
||||
*/
|
||||
inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope)
|
||||
{
|
||||
return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f);
|
||||
#define DEFINE_ALFILTER_VTABLE(T) \
|
||||
const struct ALfilterVtable T##_vtable = { \
|
||||
T##_setParami, T##_setParamiv, \
|
||||
T##_setParamf, T##_setParamfv, \
|
||||
T##_getParami, T##_getParamiv, \
|
||||
T##_getParamf, T##_getParamfv, \
|
||||
}
|
||||
/* Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the frequency
|
||||
* multiple (i.e. ref_freq / sampling_freq) and bandwidth.
|
||||
* 0 < freq_mult < 0.5.
|
||||
*/
|
||||
inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth)
|
||||
{
|
||||
ALfloat w0 = F_TAU * freq_mult;
|
||||
return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0));
|
||||
}
|
||||
|
||||
inline void ALfilterState_clear(ALfilterState *filter)
|
||||
{
|
||||
filter->x[0] = 0.0f;
|
||||
filter->x[1] = 0.0f;
|
||||
filter->y[0] = 0.0f;
|
||||
filter->y[1] = 0.0f;
|
||||
}
|
||||
|
||||
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ);
|
||||
|
||||
inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src)
|
||||
{
|
||||
dst->b0 = src->b0;
|
||||
dst->b1 = src->b1;
|
||||
dst->b2 = src->b2;
|
||||
dst->a1 = src->a1;
|
||||
dst->a2 = src->a2;
|
||||
}
|
||||
|
||||
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples);
|
||||
|
||||
inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples)
|
||||
{
|
||||
if(numsamples >= 2)
|
||||
{
|
||||
filter->x[1] = src[numsamples-2];
|
||||
filter->x[0] = src[numsamples-1];
|
||||
filter->y[1] = src[numsamples-2];
|
||||
filter->y[0] = src[numsamples-1];
|
||||
}
|
||||
else if(numsamples == 1)
|
||||
{
|
||||
filter->x[1] = filter->x[0];
|
||||
filter->x[0] = src[0];
|
||||
filter->y[1] = filter->y[0];
|
||||
filter->y[0] = src[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct ALfilter {
|
||||
// Filter type (AL_FILTER_NULL, ...)
|
||||
@@ -117,45 +44,21 @@ typedef struct ALfilter {
|
||||
ALfloat GainLF;
|
||||
ALfloat LFReference;
|
||||
|
||||
void (*SetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val);
|
||||
void (*SetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals);
|
||||
void (*SetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val);
|
||||
void (*SetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals);
|
||||
|
||||
void (*GetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val);
|
||||
void (*GetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals);
|
||||
void (*GetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val);
|
||||
void (*GetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals);
|
||||
const struct ALfilterVtable *vtab;
|
||||
|
||||
/* Self ID */
|
||||
ALuint id;
|
||||
} ALfilter;
|
||||
#define ALfilter_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v))
|
||||
#define ALfilter_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v))
|
||||
#define ALfilter_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v))
|
||||
#define ALfilter_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v))
|
||||
#define ALfilter_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v))
|
||||
#define ALfilter_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v))
|
||||
#define ALfilter_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v))
|
||||
#define ALfilter_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v))
|
||||
|
||||
#define ALfilter_SetParami(x, c, p, v) ((x)->SetParami((x),(c),(p),(v)))
|
||||
#define ALfilter_SetParamiv(x, c, p, v) ((x)->SetParamiv((x),(c),(p),(v)))
|
||||
#define ALfilter_SetParamf(x, c, p, v) ((x)->SetParamf((x),(c),(p),(v)))
|
||||
#define ALfilter_SetParamfv(x, c, p, v) ((x)->SetParamfv((x),(c),(p),(v)))
|
||||
|
||||
#define ALfilter_GetParami(x, c, p, v) ((x)->GetParami((x),(c),(p),(v)))
|
||||
#define ALfilter_GetParamiv(x, c, p, v) ((x)->GetParamiv((x),(c),(p),(v)))
|
||||
#define ALfilter_GetParamf(x, c, p, v) ((x)->GetParamf((x),(c),(p),(v)))
|
||||
#define ALfilter_GetParamfv(x, c, p, v) ((x)->GetParamfv((x),(c),(p),(v)))
|
||||
|
||||
inline void LockFiltersRead(ALCdevice *device)
|
||||
{ LockUIntMapRead(&device->FilterMap); }
|
||||
inline void UnlockFiltersRead(ALCdevice *device)
|
||||
{ UnlockUIntMapRead(&device->FilterMap); }
|
||||
inline void LockFiltersWrite(ALCdevice *device)
|
||||
{ LockUIntMapWrite(&device->FilterMap); }
|
||||
inline void UnlockFiltersWrite(ALCdevice *device)
|
||||
{ UnlockUIntMapWrite(&device->FilterMap); }
|
||||
|
||||
inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id)
|
||||
{ return (struct ALfilter*)LookupUIntMapKeyNoLock(&device->FilterMap, id); }
|
||||
inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id)
|
||||
{ return (struct ALfilter*)RemoveUIntMapKeyNoLock(&device->FilterMap, id); }
|
||||
|
||||
ALvoid ReleaseALFilters(ALCdevice *device);
|
||||
void ReleaseALFilters(ALCdevice *device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -8,19 +8,23 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ALcontextProps {
|
||||
ALfloat DopplerFactor;
|
||||
ALfloat DopplerVelocity;
|
||||
ALfloat SpeedOfSound;
|
||||
ALboolean SourceDistanceModel;
|
||||
enum DistanceModel DistanceModel;
|
||||
ALfloat MetersPerUnit;
|
||||
|
||||
ATOMIC(struct ALcontextProps*) next;
|
||||
};
|
||||
|
||||
struct ALlistenerProps {
|
||||
ALfloat Position[3];
|
||||
ALfloat Velocity[3];
|
||||
ALfloat Forward[3];
|
||||
ALfloat Up[3];
|
||||
ALfloat Gain;
|
||||
ALfloat MetersPerUnit;
|
||||
|
||||
ALfloat DopplerFactor;
|
||||
ALfloat DopplerVelocity;
|
||||
ALfloat SpeedOfSound;
|
||||
ALboolean SourceDistanceModel;
|
||||
enum DistanceModel DistanceModel;
|
||||
|
||||
ATOMIC(struct ALlistenerProps*) next;
|
||||
};
|
||||
@@ -31,17 +35,13 @@ typedef struct ALlistener {
|
||||
ALfloat Forward[3];
|
||||
ALfloat Up[3];
|
||||
ALfloat Gain;
|
||||
ALfloat MetersPerUnit;
|
||||
|
||||
ATOMIC_FLAG PropsClean;
|
||||
|
||||
/* Pointer to the most recent property values that are awaiting an update.
|
||||
*/
|
||||
ATOMIC(struct ALlistenerProps*) Update;
|
||||
|
||||
/* A linked list of unused property containers, free to use for future
|
||||
* updates.
|
||||
*/
|
||||
ATOMIC(struct ALlistenerProps*) FreeList;
|
||||
|
||||
struct {
|
||||
aluMatrixf Matrix;
|
||||
aluVector Velocity;
|
||||
@@ -50,7 +50,8 @@ typedef struct ALlistener {
|
||||
ALfloat MetersPerUnit;
|
||||
|
||||
ALfloat DopplerFactor;
|
||||
ALfloat SpeedOfSound;
|
||||
ALfloat SpeedOfSound; /* in units per sec! */
|
||||
ALfloat ReverbSpeedOfSound; /* in meters per sec! */
|
||||
|
||||
ALboolean SourceDistanceModel;
|
||||
enum DistanceModel DistanceModel;
|
||||
|
||||
@@ -12,133 +12,25 @@
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FENV_H
|
||||
#include <fenv.h>
|
||||
#ifdef HAVE_INTRIN_H
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/alext.h"
|
||||
|
||||
#include "inprogext.h"
|
||||
#include "logging.h"
|
||||
#include "polymorphism.h"
|
||||
#include "static_assert.h"
|
||||
#include "align.h"
|
||||
#include "atomic.h"
|
||||
#include "uintmap.h"
|
||||
#include "vector.h"
|
||||
#include "alstring.h"
|
||||
#include "almalloc.h"
|
||||
#include "threads.h"
|
||||
|
||||
#ifndef ALC_SOFT_loopback2
|
||||
#define ALC_SOFT_loopback2 1
|
||||
#define ALC_AMBISONIC_LAYOUT_SOFT 0x1997
|
||||
#define ALC_AMBISONIC_SCALING_SOFT 0x1998
|
||||
#define ALC_AMBISONIC_ORDER_SOFT 0x1999
|
||||
|
||||
#define ALC_BFORMAT3D_SOFT 0x1508
|
||||
|
||||
/* Ambisonic layouts */
|
||||
#define ALC_ACN_SOFT 0x1600
|
||||
#define ALC_FUMA_SOFT 0x1601
|
||||
|
||||
/* Ambisonic scalings (normalization) */
|
||||
/*#define ALC_FUMA_SOFT*/
|
||||
#define ALC_SN3D_SOFT 0x1602
|
||||
#define ALC_N3D_SOFT 0x1603
|
||||
|
||||
typedef ALCboolean (ALC_APIENTRY*LPALCISAMBISONICFORMATSUPPORTEDSOFT)(ALCdevice *device, ALCenum layout, ALCenum scaling, ALsizei order);
|
||||
#ifdef AL_ALEXT_PROTOTYPES
|
||||
ALC_API ALCboolean ALC_APIENTRY alcIsAmbisonicFormatSupportedSOFT(ALCdevice *device, ALCenum layout, ALCenum scaling, ALsizei order);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ALC_SOFT_device_clock
|
||||
#define ALC_SOFT_device_clock 1
|
||||
typedef int64_t ALCint64SOFT;
|
||||
typedef uint64_t ALCuint64SOFT;
|
||||
#define ALC_DEVICE_CLOCK_SOFT 0x1600
|
||||
#define ALC_DEVICE_LATENCY_SOFT 0x1601
|
||||
#define ALC_DEVICE_CLOCK_LATENCY_SOFT 0x1602
|
||||
typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values);
|
||||
#ifdef AL_ALEXT_PROTOTYPES
|
||||
ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef AL_SOFT_buffer_samples2
|
||||
#define AL_SOFT_buffer_samples2 1
|
||||
/* Channel configurations */
|
||||
#define AL_MONO_SOFT 0x1500
|
||||
#define AL_STEREO_SOFT 0x1501
|
||||
#define AL_REAR_SOFT 0x1502
|
||||
#define AL_QUAD_SOFT 0x1503
|
||||
#define AL_5POINT1_SOFT 0x1504
|
||||
#define AL_6POINT1_SOFT 0x1505
|
||||
#define AL_7POINT1_SOFT 0x1506
|
||||
#define AL_BFORMAT2D_SOFT 0x1507
|
||||
#define AL_BFORMAT3D_SOFT 0x1508
|
||||
|
||||
/* Sample types */
|
||||
#define AL_BYTE_SOFT 0x1400
|
||||
#define AL_UNSIGNED_BYTE_SOFT 0x1401
|
||||
#define AL_SHORT_SOFT 0x1402
|
||||
#define AL_UNSIGNED_SHORT_SOFT 0x1403
|
||||
#define AL_INT_SOFT 0x1404
|
||||
#define AL_UNSIGNED_INT_SOFT 0x1405
|
||||
#define AL_FLOAT_SOFT 0x1406
|
||||
#define AL_DOUBLE_SOFT 0x1407
|
||||
#define AL_BYTE3_SOFT 0x1408
|
||||
#define AL_UNSIGNED_BYTE3_SOFT 0x1409
|
||||
#define AL_MULAW_SOFT 0x140A
|
||||
|
||||
/* Storage formats */
|
||||
#define AL_MONO8_SOFT 0x1100
|
||||
#define AL_MONO16_SOFT 0x1101
|
||||
#define AL_MONO32F_SOFT 0x10010
|
||||
#define AL_STEREO8_SOFT 0x1102
|
||||
#define AL_STEREO16_SOFT 0x1103
|
||||
#define AL_STEREO32F_SOFT 0x10011
|
||||
#define AL_QUAD8_SOFT 0x1204
|
||||
#define AL_QUAD16_SOFT 0x1205
|
||||
#define AL_QUAD32F_SOFT 0x1206
|
||||
#define AL_REAR8_SOFT 0x1207
|
||||
#define AL_REAR16_SOFT 0x1208
|
||||
#define AL_REAR32F_SOFT 0x1209
|
||||
#define AL_5POINT1_8_SOFT 0x120A
|
||||
#define AL_5POINT1_16_SOFT 0x120B
|
||||
#define AL_5POINT1_32F_SOFT 0x120C
|
||||
#define AL_6POINT1_8_SOFT 0x120D
|
||||
#define AL_6POINT1_16_SOFT 0x120E
|
||||
#define AL_6POINT1_32F_SOFT 0x120F
|
||||
#define AL_7POINT1_8_SOFT 0x1210
|
||||
#define AL_7POINT1_16_SOFT 0x1211
|
||||
#define AL_7POINT1_32F_SOFT 0x1212
|
||||
#define AL_BFORMAT2D_8_SOFT 0x20021
|
||||
#define AL_BFORMAT2D_16_SOFT 0x20022
|
||||
#define AL_BFORMAT2D_32F_SOFT 0x20023
|
||||
#define AL_BFORMAT3D_8_SOFT 0x20031
|
||||
#define AL_BFORMAT3D_16_SOFT 0x20032
|
||||
#define AL_BFORMAT3D_32F_SOFT 0x20033
|
||||
|
||||
/* Buffer attributes */
|
||||
#define AL_INTERNAL_FORMAT_SOFT 0x2008
|
||||
#define AL_BYTE_LENGTH_SOFT 0x2009
|
||||
#define AL_SAMPLE_LENGTH_SOFT 0x200A
|
||||
#define AL_SEC_LENGTH_SOFT 0x200B
|
||||
|
||||
#if 0
|
||||
typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*);
|
||||
typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*);
|
||||
typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum);
|
||||
#ifdef AL_ALEXT_PROTOTYPES
|
||||
AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data);
|
||||
AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data);
|
||||
AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_WIN64)
|
||||
#define SZFMT "%I64u"
|
||||
@@ -150,72 +42,11 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format);
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
/* Because of a long-standing deficiency in C, you're not allowed to implicitly
|
||||
* cast a pointer-to-type-array to a pointer-to-const-type-array. For example,
|
||||
*
|
||||
* int (*ptr)[10];
|
||||
* const int (*cptr)[10] = ptr;
|
||||
*
|
||||
* is not allowed and most compilers will generate noisy warnings about
|
||||
* incompatible types, even though it just makes the array elements const.
|
||||
* Clang will allow it if you make the array type a typedef, like this:
|
||||
*
|
||||
* typedef int int10[10];
|
||||
* int10 *ptr;
|
||||
* const int10 *cptr = ptr;
|
||||
*
|
||||
* however GCC does not and still issues the incompatible type warning. The
|
||||
* "proper" way to fix it is to add an explicit cast for the constified type,
|
||||
* but that removes the vast majority of otherwise useful type-checking you'd
|
||||
* get, and runs the risk of improper casts if types are later changed. Leaving
|
||||
* it non-const can also be an issue if you use it as a function parameter, and
|
||||
* happen to have a const type as input (and also reduce the capabilities of
|
||||
* the compiler to better optimize the function).
|
||||
*
|
||||
* So to work around the problem, we use a macro. The macro first assigns the
|
||||
* incoming variable to the specified non-const type to ensure it's the correct
|
||||
* type, then casts the variable as the desired constified type. Very ugly, but
|
||||
* I'd rather not have hundreds of lines of warnings because I want to tell the
|
||||
* compiler that some array(s) can't be changed by the code, or have lots of
|
||||
* error-prone casts.
|
||||
*/
|
||||
#define SAFE_CONST(T, var) __extension__({ \
|
||||
T _tmp = (var); \
|
||||
(const T)_tmp; \
|
||||
})
|
||||
#define LIKELY(x) __builtin_expect(!!(x), !0)
|
||||
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
/* Non-GNU-compatible compilers have to use a straight cast with no extra
|
||||
* checks, due to the lack of multi-statement expressions.
|
||||
*/
|
||||
#define SAFE_CONST(T, var) ((const T)(var))
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
/* This helps cast away the const-ness of a pointer without accidentally
|
||||
* changing the pointer type. This is necessary due to Clang's inability to use
|
||||
* atomic_load on a const _Atomic variable.
|
||||
*/
|
||||
#define CONST_CAST(T, V) __extension__({ \
|
||||
const T _tmp = (V); \
|
||||
(T)_tmp; \
|
||||
})
|
||||
#else
|
||||
#define CONST_CAST(T, V) ((T)(V))
|
||||
#endif
|
||||
|
||||
|
||||
typedef ALint64SOFT ALint64;
|
||||
typedef ALuint64SOFT ALuint64;
|
||||
|
||||
#ifndef U64
|
||||
#if defined(_MSC_VER)
|
||||
#define U64(x) ((ALuint64)(x##ui64))
|
||||
#elif SIZEOF_LONG == 8
|
||||
#define U64(x) ((ALuint64)(x##ul))
|
||||
#elif SIZEOF_LONG_LONG == 8
|
||||
#define U64(x) ((ALuint64)(x##ull))
|
||||
#endif
|
||||
#define LIKELY(x) (!!(x))
|
||||
#define UNLIKELY(x) (!!(x))
|
||||
#endif
|
||||
|
||||
#ifndef UINT64_MAX
|
||||
@@ -234,42 +65,88 @@ typedef ALuint64SOFT ALuint64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z))))
|
||||
#else
|
||||
#define DECL_FORMAT(x, y, z)
|
||||
#endif
|
||||
|
||||
/* Calculates the size of a struct with N elements of a flexible array member.
|
||||
* GCC and Clang allow offsetof(Type, fam[N]) for this, but MSVC seems to have
|
||||
* trouble, so a bit more verbose workaround is needed.
|
||||
*/
|
||||
#define FAM_SIZE(T, M, N) (offsetof(T, M) + sizeof(((T*)NULL)->M[0])*(N))
|
||||
|
||||
#if defined(__GNUC__) && defined(__i386__)
|
||||
/* force_align_arg_pointer is required for proper function arguments aligning
|
||||
* when SSE code is used. Some systems (Windows, QNX) do not guarantee our
|
||||
* thread functions will be properly aligned on the stack, even though GCC may
|
||||
* generate code with the assumption that it is. */
|
||||
#define FORCE_ALIGN __attribute__((force_align_arg_pointer))
|
||||
#else
|
||||
#define FORCE_ALIGN
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_C99_VLA
|
||||
#define DECL_VLA(T, _name, _size) T _name[(_size)]
|
||||
#else
|
||||
#define DECL_VLA(T, _name, _size) T *_name = alloca((_size) * sizeof(T))
|
||||
#endif
|
||||
typedef ALint64SOFT ALint64;
|
||||
typedef ALuint64SOFT ALuint64;
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#ifdef MAX_PATH
|
||||
#define PATH_MAX MAX_PATH
|
||||
#else
|
||||
#define PATH_MAX 4096
|
||||
#ifndef U64
|
||||
#if defined(_MSC_VER)
|
||||
#define U64(x) ((ALuint64)(x##ui64))
|
||||
#elif SIZEOF_LONG == 8
|
||||
#define U64(x) ((ALuint64)(x##ul))
|
||||
#elif SIZEOF_LONG_LONG == 8
|
||||
#define U64(x) ((ALuint64)(x##ull))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define a CTZ64 macro (count trailing zeros, for 64-bit integers). The result
|
||||
* is *UNDEFINED* if the value is 0.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if SIZEOF_LONG == 8
|
||||
#define CTZ64(x) __builtin_ctzl(x)
|
||||
#else
|
||||
#define CTZ64(x) __builtin_ctzll(x)
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_BITSCANFORWARD64_INTRINSIC)
|
||||
|
||||
inline int msvc64_ctz64(ALuint64 v)
|
||||
{
|
||||
unsigned long idx = 64;
|
||||
_BitScanForward64(&idx, v);
|
||||
return (int)idx;
|
||||
}
|
||||
#define CTZ64(x) msvc64_ctz64(x)
|
||||
|
||||
#elif defined(HAVE_BITSCANFORWARD_INTRINSIC)
|
||||
|
||||
inline int msvc_ctz64(ALuint64 v)
|
||||
{
|
||||
unsigned long idx = 64;
|
||||
if(!_BitScanForward(&idx, v&0xffffffff))
|
||||
{
|
||||
if(_BitScanForward(&idx, v>>32))
|
||||
idx += 32;
|
||||
}
|
||||
return (int)idx;
|
||||
}
|
||||
#define CTZ64(x) msvc_ctz64(x)
|
||||
|
||||
#else
|
||||
|
||||
/* There be black magics here. The popcnt64 method is derived from
|
||||
* https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
|
||||
* while the ctz-utilizing-popcnt algorithm is shown here
|
||||
* http://www.hackersdelight.org/hdcodetxt/ntz.c.txt
|
||||
* as the ntz2 variant. These likely aren't the most efficient methods, but
|
||||
* they're good enough if the GCC or MSVC intrinsics aren't available.
|
||||
*/
|
||||
inline int fallback_popcnt64(ALuint64 v)
|
||||
{
|
||||
v = v - ((v >> 1) & U64(0x5555555555555555));
|
||||
v = (v & U64(0x3333333333333333)) + ((v >> 2) & U64(0x3333333333333333));
|
||||
v = (v + (v >> 4)) & U64(0x0f0f0f0f0f0f0f0f);
|
||||
return (int)((v * U64(0x0101010101010101)) >> 56);
|
||||
}
|
||||
|
||||
inline int fallback_ctz64(ALuint64 value)
|
||||
{
|
||||
return fallback_popcnt64(~value & (value - 1));
|
||||
}
|
||||
#define CTZ64(x) fallback_ctz64(x)
|
||||
#endif
|
||||
|
||||
static const union {
|
||||
ALuint u;
|
||||
@@ -280,107 +157,21 @@ static const union {
|
||||
#define COUNTOF(x) (sizeof(x) / sizeof(0[x]))
|
||||
|
||||
|
||||
#define DERIVE_FROM_TYPE(t) t t##_parent
|
||||
#define STATIC_CAST(to, obj) (&(obj)->to##_parent)
|
||||
#ifdef __GNUC__
|
||||
#define STATIC_UPCAST(to, from, obj) __extension__({ \
|
||||
static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \
|
||||
"Invalid upcast object from type"); \
|
||||
(to*)((char*)(obj) - offsetof(to, from##_parent)); \
|
||||
})
|
||||
#else
|
||||
#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent)))
|
||||
#endif
|
||||
|
||||
#define DECLARE_FORWARD(T1, T2, rettype, func) \
|
||||
rettype T1##_##func(T1 *obj) \
|
||||
{ return T2##_##func(STATIC_CAST(T2, obj)); }
|
||||
|
||||
#define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \
|
||||
rettype T1##_##func(T1 *obj, argtype1 a) \
|
||||
{ return T2##_##func(STATIC_CAST(T2, obj), a); }
|
||||
|
||||
#define DECLARE_FORWARD2(T1, T2, rettype, func, argtype1, argtype2) \
|
||||
rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b) \
|
||||
{ return T2##_##func(STATIC_CAST(T2, obj), a, b); }
|
||||
|
||||
#define DECLARE_FORWARD3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
|
||||
rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b, argtype3 c) \
|
||||
{ return T2##_##func(STATIC_CAST(T2, obj), a, b, c); }
|
||||
|
||||
|
||||
#define GET_VTABLE1(T1) (&(T1##_vtable))
|
||||
#define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable))
|
||||
|
||||
#define SET_VTABLE1(T1, obj) ((obj)->vtbl = GET_VTABLE1(T1))
|
||||
#define SET_VTABLE2(T1, T2, obj) (STATIC_CAST(T2, obj)->vtbl = GET_VTABLE2(T1, T2))
|
||||
|
||||
#define DECLARE_THUNK(T1, T2, rettype, func) \
|
||||
static rettype T1##_##T2##_##func(T2 *obj) \
|
||||
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj)); }
|
||||
|
||||
#define DECLARE_THUNK1(T1, T2, rettype, func, argtype1) \
|
||||
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a) \
|
||||
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a); }
|
||||
|
||||
#define DECLARE_THUNK2(T1, T2, rettype, func, argtype1, argtype2) \
|
||||
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \
|
||||
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b); }
|
||||
|
||||
#define DECLARE_THUNK3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
|
||||
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \
|
||||
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); }
|
||||
|
||||
#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \
|
||||
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \
|
||||
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); }
|
||||
|
||||
#define DECLARE_DEFAULT_ALLOCATORS(T) \
|
||||
static void* T##_New(size_t size) { return al_malloc(16, size); } \
|
||||
static void T##_Delete(void *ptr) { al_free(ptr); }
|
||||
|
||||
/* Helper to extract an argument list for VCALL. Not used directly. */
|
||||
#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
|
||||
|
||||
/* Call a "virtual" method on an object, with arguments. */
|
||||
#define V(obj, func) ((obj)->vtbl->func((obj), EXTRACT_VCALL_ARGS
|
||||
/* Call a "virtual" method on an object, with no arguments. */
|
||||
#define V0(obj, func) ((obj)->vtbl->func((obj) EXTRACT_VCALL_ARGS
|
||||
|
||||
#define DELETE_OBJ(obj) do { \
|
||||
if((obj) != NULL) \
|
||||
{ \
|
||||
V0((obj),Destruct)(); \
|
||||
V0((obj),Delete)(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define NEW_OBJ(_res, T) do { \
|
||||
_res = T##_New(sizeof(T)); \
|
||||
if(_res) \
|
||||
{ \
|
||||
memset(_res, 0, sizeof(T)); \
|
||||
T##_Construct(_res, EXTRACT_NEW_ARGS
|
||||
#define NEW_OBJ0(_res, T) do { \
|
||||
_res = T##_New(sizeof(T)); \
|
||||
if(_res) \
|
||||
{ \
|
||||
memset(_res, 0, sizeof(T)); \
|
||||
T##_Construct(_res EXTRACT_NEW_ARGS
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ll_ringbuffer;
|
||||
struct Hrtf;
|
||||
struct HrtfEntry;
|
||||
struct DirectHrtfState;
|
||||
struct FrontStablizer;
|
||||
struct Compressor;
|
||||
struct ALCbackend;
|
||||
struct ALbuffer;
|
||||
struct ALeffect;
|
||||
struct ALfilter;
|
||||
struct ALsource;
|
||||
struct ALcontextProps;
|
||||
struct ALlistenerProps;
|
||||
struct ALvoiceProps;
|
||||
struct ALeffectslotProps;
|
||||
|
||||
|
||||
#define DEFAULT_OUTPUT_RATE (44100)
|
||||
@@ -409,24 +200,6 @@ inline size_t RoundUp(size_t value, size_t r)
|
||||
return value - (value%r);
|
||||
}
|
||||
|
||||
/* Scales the given value using 64-bit integer math, rounding the result. */
|
||||
inline ALuint64 ScaleRound(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale)
|
||||
{
|
||||
return (val*new_scale + old_scale/2) / old_scale;
|
||||
}
|
||||
|
||||
/* Scales the given value using 64-bit integer math, flooring the result. */
|
||||
inline ALuint64 ScaleFloor(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale)
|
||||
{
|
||||
return val * new_scale / old_scale;
|
||||
}
|
||||
|
||||
/* Scales the given value using 64-bit integer math, ceiling the result. */
|
||||
inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale)
|
||||
{
|
||||
return (val*new_scale + old_scale-1) / old_scale;
|
||||
}
|
||||
|
||||
/* Fast float-to-int conversion. Assumes the FPU is already in round-to-zero
|
||||
* mode. */
|
||||
inline ALint fastf2i(ALfloat f)
|
||||
@@ -449,8 +222,6 @@ enum DevProbe {
|
||||
CAPTURE_DEVICE_PROBE
|
||||
};
|
||||
|
||||
struct ALCbackend;
|
||||
|
||||
|
||||
enum DistanceModel {
|
||||
InverseDistanceClamped = AL_INVERSE_DISTANCE_CLAMPED,
|
||||
@@ -556,14 +327,6 @@ enum AmbiNorm {
|
||||
};
|
||||
|
||||
|
||||
extern const struct EffectList {
|
||||
const char *name;
|
||||
int type;
|
||||
const char *ename;
|
||||
ALenum val;
|
||||
} EffectList[];
|
||||
|
||||
|
||||
enum DeviceType {
|
||||
Playback,
|
||||
Capture,
|
||||
@@ -614,34 +377,36 @@ typedef union AmbiConfig {
|
||||
} AmbiConfig;
|
||||
|
||||
|
||||
#define HRTF_HISTORY_BITS (6)
|
||||
#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
|
||||
#define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1)
|
||||
typedef struct BufferSubList {
|
||||
ALuint64 FreeMask;
|
||||
struct ALbuffer *Buffers; /* 64 */
|
||||
} BufferSubList;
|
||||
TYPEDEF_VECTOR(BufferSubList, vector_BufferSubList)
|
||||
|
||||
#define HRIR_BITS (7)
|
||||
#define HRIR_LENGTH (1<<HRIR_BITS)
|
||||
#define HRIR_MASK (HRIR_LENGTH-1)
|
||||
typedef struct EffectSubList {
|
||||
ALuint64 FreeMask;
|
||||
struct ALeffect *Effects; /* 64 */
|
||||
} EffectSubList;
|
||||
TYPEDEF_VECTOR(EffectSubList, vector_EffectSubList)
|
||||
|
||||
typedef struct HrtfState {
|
||||
alignas(16) ALfloat History[HRTF_HISTORY_LENGTH];
|
||||
alignas(16) ALfloat Values[HRIR_LENGTH][2];
|
||||
} HrtfState;
|
||||
typedef struct FilterSubList {
|
||||
ALuint64 FreeMask;
|
||||
struct ALfilter *Filters; /* 64 */
|
||||
} FilterSubList;
|
||||
TYPEDEF_VECTOR(FilterSubList, vector_FilterSubList)
|
||||
|
||||
typedef struct HrtfParams {
|
||||
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
|
||||
ALsizei Delay[2];
|
||||
ALfloat Gain;
|
||||
} HrtfParams;
|
||||
typedef struct SourceSubList {
|
||||
ALuint64 FreeMask;
|
||||
struct ALsource *Sources; /* 64 */
|
||||
} SourceSubList;
|
||||
TYPEDEF_VECTOR(SourceSubList, vector_SourceSubList)
|
||||
|
||||
/* Effect slots are rather large, and apps aren't likely to have more than one
|
||||
* or two (let alone 64), so hold them individually.
|
||||
*/
|
||||
typedef struct ALeffectslot *ALeffectslotPtr;
|
||||
TYPEDEF_VECTOR(ALeffectslotPtr, vector_ALeffectslotPtr)
|
||||
|
||||
typedef struct DirectHrtfState {
|
||||
/* HRTF filter state for dry buffer content */
|
||||
ALsizei Offset;
|
||||
ALsizei IrSize;
|
||||
struct {
|
||||
alignas(16) ALfloat Values[HRIR_LENGTH][2];
|
||||
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
|
||||
} Chan[];
|
||||
} DirectHrtfState;
|
||||
|
||||
typedef struct EnumeratedHrtf {
|
||||
al_string name;
|
||||
@@ -667,11 +432,41 @@ typedef struct DistanceComp {
|
||||
*/
|
||||
#define BUFFERSIZE 2048
|
||||
|
||||
struct ALCdevice_struct
|
||||
{
|
||||
typedef struct DryMixParams {
|
||||
AmbiConfig Ambi;
|
||||
/* Number of coefficients in each Ambi.Coeffs to mix together (4 for first-
|
||||
* order, 9 for second-order, etc). If the count is 0, Ambi.Map is used
|
||||
* instead to map each output to a coefficient index.
|
||||
*/
|
||||
ALsizei CoeffCount;
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1];
|
||||
} DryMixParams;
|
||||
|
||||
typedef struct BFMixParams {
|
||||
AmbiConfig Ambi;
|
||||
/* Will only be 4 or 0. */
|
||||
ALsizei CoeffCount;
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
} BFMixParams;
|
||||
|
||||
typedef struct RealMixParams {
|
||||
enum Channel ChannelName[MAX_OUTPUT_CHANNELS];
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
} RealMixParams;
|
||||
|
||||
typedef void (*POSTPROCESS)(ALCdevice *device, ALsizei SamplesToDo);
|
||||
|
||||
struct ALCdevice_struct {
|
||||
RefCount ref;
|
||||
|
||||
ALCboolean Connected;
|
||||
ATOMIC(ALenum) Connected;
|
||||
enum DeviceType Type;
|
||||
|
||||
ALuint Frequency;
|
||||
@@ -701,16 +496,21 @@ struct ALCdevice_struct
|
||||
ALsizei NumAuxSends;
|
||||
|
||||
// Map of Buffers for this device
|
||||
UIntMap BufferMap;
|
||||
vector_BufferSubList BufferList;
|
||||
almtx_t BufferLock;
|
||||
|
||||
// Map of Effects for this device
|
||||
UIntMap EffectMap;
|
||||
vector_EffectSubList EffectList;
|
||||
almtx_t EffectLock;
|
||||
|
||||
// Map of Filters for this device
|
||||
UIntMap FilterMap;
|
||||
vector_FilterSubList FilterList;
|
||||
almtx_t FilterLock;
|
||||
|
||||
POSTPROCESS PostProcess;
|
||||
|
||||
/* HRTF state and info */
|
||||
DirectHrtfState *Hrtf;
|
||||
struct DirectHrtfState *Hrtf;
|
||||
al_string HrtfName;
|
||||
struct Hrtf *HrtfHandle;
|
||||
vector_EnumeratedHrtf HrtfList;
|
||||
@@ -737,45 +537,21 @@ struct ALCdevice_struct
|
||||
ALuint64 ClockBase;
|
||||
ALuint SamplesDone;
|
||||
|
||||
/* Temp storage used for each source when mixing. */
|
||||
alignas(16) ALfloat SourceData[BUFFERSIZE];
|
||||
alignas(16) ALfloat ResampledData[BUFFERSIZE];
|
||||
alignas(16) ALfloat FilteredData[BUFFERSIZE];
|
||||
alignas(16) ALfloat NFCtrlData[BUFFERSIZE];
|
||||
/* Temp storage used for mixer processing. */
|
||||
alignas(16) ALfloat TempBuffer[4][BUFFERSIZE];
|
||||
|
||||
/* The "dry" path corresponds to the main output. */
|
||||
struct {
|
||||
AmbiConfig Ambi;
|
||||
/* Number of coefficients in each Ambi.Coeffs to mix together (4 for
|
||||
* first-order, 9 for second-order, etc). If the count is 0, Ambi.Map
|
||||
* is used instead to map each output to a coefficient index.
|
||||
*/
|
||||
ALsizei CoeffCount;
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1];
|
||||
} Dry;
|
||||
DryMixParams Dry;
|
||||
|
||||
/* First-order ambisonics output, to be upsampled to the dry buffer if different. */
|
||||
struct {
|
||||
AmbiConfig Ambi;
|
||||
/* Will only be 4 or 0. */
|
||||
ALsizei CoeffCount;
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
} FOAOut;
|
||||
BFMixParams FOAOut;
|
||||
|
||||
/* "Real" output, which will be written to the device buffer. May alias the
|
||||
* dry buffer.
|
||||
*/
|
||||
struct {
|
||||
enum Channel ChannelName[MAX_OUTPUT_CHANNELS];
|
||||
RealMixParams RealOut;
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
} RealOut;
|
||||
struct FrontStablizer *Stablizer;
|
||||
|
||||
struct Compressor *Limiter;
|
||||
|
||||
@@ -804,7 +580,7 @@ struct ALCdevice_struct
|
||||
almtx_t BackendLock;
|
||||
struct ALCbackend *Backend;
|
||||
|
||||
ALCdevice *volatile next;
|
||||
ATOMIC(ALCdevice*) next;
|
||||
};
|
||||
|
||||
// Frequency was requested by the app or config file
|
||||
@@ -832,13 +608,34 @@ struct ALCdevice_struct
|
||||
#define RECORD_THREAD_NAME "alsoft-record"
|
||||
|
||||
|
||||
enum {
|
||||
EventType_SourceStateChange = 1<<0,
|
||||
EventType_BufferCompleted = 1<<1,
|
||||
EventType_Error = 1<<2,
|
||||
EventType_Performance = 1<<3,
|
||||
EventType_Deprecated = 1<<4,
|
||||
EventType_Disconnected = 1<<5,
|
||||
};
|
||||
|
||||
typedef struct AsyncEvent {
|
||||
unsigned int EnumType;
|
||||
ALenum Type;
|
||||
ALuint ObjectId;
|
||||
ALuint Param;
|
||||
ALchar Message[1008];
|
||||
} AsyncEvent;
|
||||
|
||||
struct ALCcontext_struct {
|
||||
RefCount ref;
|
||||
|
||||
struct ALlistener *Listener;
|
||||
|
||||
UIntMap SourceMap;
|
||||
UIntMap EffectSlotMap;
|
||||
vector_SourceSubList SourceList;
|
||||
ALuint NumSources;
|
||||
almtx_t SourceLock;
|
||||
|
||||
vector_ALeffectslotPtr EffectSlotList;
|
||||
almtx_t EffectSlotLock;
|
||||
|
||||
ATOMIC(ALenum) LastError;
|
||||
|
||||
@@ -848,9 +645,12 @@ struct ALCcontext_struct {
|
||||
ALfloat DopplerFactor;
|
||||
ALfloat DopplerVelocity;
|
||||
ALfloat SpeedOfSound;
|
||||
ALfloat MetersPerUnit;
|
||||
|
||||
ATOMIC_FLAG PropsClean;
|
||||
ATOMIC(ALenum) DeferUpdates;
|
||||
|
||||
RWLock PropLock;
|
||||
almtx_t PropLock;
|
||||
|
||||
/* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
|
||||
* indicates if updates are currently happening).
|
||||
@@ -860,19 +660,38 @@ struct ALCcontext_struct {
|
||||
|
||||
ALfloat GainBoost;
|
||||
|
||||
ATOMIC(struct ALcontextProps*) Update;
|
||||
|
||||
/* Linked lists of unused property containers, free to use for future
|
||||
* updates.
|
||||
*/
|
||||
ATOMIC(struct ALcontextProps*) FreeContextProps;
|
||||
ATOMIC(struct ALlistenerProps*) FreeListenerProps;
|
||||
ATOMIC(struct ALvoiceProps*) FreeVoiceProps;
|
||||
ATOMIC(struct ALeffectslotProps*) FreeEffectslotProps;
|
||||
|
||||
struct ALvoice **Voices;
|
||||
ALsizei VoiceCount;
|
||||
ALsizei MaxVoices;
|
||||
|
||||
ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots;
|
||||
|
||||
almtx_t EventThrdLock;
|
||||
althrd_t EventThread;
|
||||
alsem_t EventSem;
|
||||
struct ll_ringbuffer *AsyncEvents;
|
||||
ATOMIC(ALbitfieldSOFT) EnabledEvts;
|
||||
almtx_t EventCbLock;
|
||||
ALEVENTPROCSOFT EventCb;
|
||||
void *EventParam;
|
||||
|
||||
/* Default effect slot */
|
||||
struct ALeffectslot *DefaultSlot;
|
||||
|
||||
ALCdevice *Device;
|
||||
const ALCchar *ExtensionList;
|
||||
|
||||
ALCcontext *volatile next;
|
||||
ATOMIC(ALCcontext*) next;
|
||||
|
||||
/* Memory space used by the listener (and possibly default effect slot) */
|
||||
alignas(16) ALCbyte _listener_mem[];
|
||||
@@ -880,79 +699,18 @@ struct ALCcontext_struct {
|
||||
|
||||
ALCcontext *GetContextRef(void);
|
||||
|
||||
void ALCcontext_IncRef(ALCcontext *context);
|
||||
void ALCcontext_DecRef(ALCcontext *context);
|
||||
|
||||
void ALCcontext_DeferUpdates(ALCcontext *context);
|
||||
void ALCcontext_ProcessUpdates(ALCcontext *context);
|
||||
|
||||
void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends);
|
||||
|
||||
void AppendAllDevicesList(const ALCchar *name);
|
||||
void AppendCaptureDeviceList(const ALCchar *name);
|
||||
|
||||
void ALCdevice_Lock(ALCdevice *device);
|
||||
void ALCdevice_Unlock(ALCdevice *device);
|
||||
|
||||
void ALCcontext_DeferUpdates(ALCcontext *context);
|
||||
void ALCcontext_ProcessUpdates(ALCcontext *context);
|
||||
|
||||
|
||||
typedef struct {
|
||||
#ifdef HAVE_FENV_H
|
||||
DERIVE_FROM_TYPE(fenv_t);
|
||||
#ifdef _WIN32
|
||||
int round_mode;
|
||||
#endif
|
||||
#else
|
||||
int state;
|
||||
#endif
|
||||
#ifdef HAVE_SSE
|
||||
int sse_state;
|
||||
#endif
|
||||
} FPUCtl;
|
||||
void SetMixerFPUMode(FPUCtl *ctl);
|
||||
void RestoreFPUMode(const FPUCtl *ctl);
|
||||
#ifdef __GNUC__
|
||||
/* Use an alternate macro set with GCC to avoid accidental continue or break
|
||||
* statements within the mixer mode.
|
||||
*/
|
||||
#define START_MIXER_MODE() __extension__({ FPUCtl _oldMode; SetMixerFPUMode(&_oldMode);
|
||||
#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); })
|
||||
#else
|
||||
#define START_MIXER_MODE() do { FPUCtl _oldMode; SetMixerFPUMode(&_oldMode);
|
||||
#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); } while(0)
|
||||
#endif
|
||||
#define LEAVE_MIXER_MODE() RestoreFPUMode(&_oldMode)
|
||||
|
||||
|
||||
typedef struct ll_ringbuffer ll_ringbuffer_t;
|
||||
typedef struct ll_ringbuffer_data {
|
||||
char *buf;
|
||||
size_t len;
|
||||
} ll_ringbuffer_data_t;
|
||||
ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz);
|
||||
void ll_ringbuffer_free(ll_ringbuffer_t *rb);
|
||||
void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec);
|
||||
void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec);
|
||||
size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt);
|
||||
size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt);
|
||||
void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt);
|
||||
size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb);
|
||||
int ll_ringbuffer_mlock(ll_ringbuffer_t *rb);
|
||||
void ll_ringbuffer_reset(ll_ringbuffer_t *rb);
|
||||
size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt);
|
||||
void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt);
|
||||
size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb);
|
||||
|
||||
void ReadALConfig(void);
|
||||
void FreeALConfig(void);
|
||||
int ConfigValueExists(const char *devName, const char *blockName, const char *keyName);
|
||||
const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def);
|
||||
int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def);
|
||||
int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret);
|
||||
int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret);
|
||||
int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret);
|
||||
int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret);
|
||||
int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret);
|
||||
|
||||
extern ALint RTPrioLevel;
|
||||
void SetRTPriority(void);
|
||||
|
||||
void SetDefaultChannelOrder(ALCdevice *device);
|
||||
@@ -961,12 +719,6 @@ void SetDefaultWFXChannelOrder(ALCdevice *device);
|
||||
const ALCchar *DevFmtTypeString(enum DevFmtType type);
|
||||
const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans);
|
||||
|
||||
/**
|
||||
* GetChannelIdxByName
|
||||
*
|
||||
* Returns the index for the given channel name (e.g. FrontCenter), or -1 if it
|
||||
* doesn't exist.
|
||||
*/
|
||||
inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan)
|
||||
{
|
||||
ALint i;
|
||||
@@ -977,107 +729,33 @@ inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#define GetChannelIdxByName(x, c) GetChannelIndex((x).ChannelName, (c))
|
||||
|
||||
extern FILE *LogFile;
|
||||
|
||||
#if defined(__GNUC__) && !defined(_WIN32) && !defined(IN_IDE_PARSER)
|
||||
#define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: "MSG, T, __FUNCTION__ , ## __VA_ARGS__)
|
||||
#else
|
||||
void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4);
|
||||
#define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s: "MSG, __FUNCTION__ , ## __VA_ARGS__)
|
||||
#else
|
||||
#define LOG_ANDROID(T, MSG, ...) ((void)0)
|
||||
#endif
|
||||
|
||||
enum LogLevel {
|
||||
NoLog,
|
||||
LogError,
|
||||
LogWarning,
|
||||
LogTrace,
|
||||
LogRef
|
||||
};
|
||||
extern enum LogLevel LogLevel;
|
||||
|
||||
#define TRACEREF(...) do { \
|
||||
if(LogLevel >= LogRef) \
|
||||
AL_PRINT("(--)", __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define TRACE(...) do { \
|
||||
if(LogLevel >= LogTrace) \
|
||||
AL_PRINT("(II)", __VA_ARGS__); \
|
||||
LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define WARN(...) do { \
|
||||
if(LogLevel >= LogWarning) \
|
||||
AL_PRINT("(WW)", __VA_ARGS__); \
|
||||
LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define ERR(...) do { \
|
||||
if(LogLevel >= LogError) \
|
||||
AL_PRINT("(EE)", __VA_ARGS__); \
|
||||
LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \
|
||||
} while(0)
|
||||
/**
|
||||
* GetChannelIdxByName
|
||||
*
|
||||
* Returns the index for the given channel name (e.g. FrontCenter), or -1 if it
|
||||
* doesn't exist.
|
||||
*/
|
||||
inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan)
|
||||
{ return GetChannelIndex(real->ChannelName, chan); }
|
||||
|
||||
|
||||
extern ALint RTPrioLevel;
|
||||
inline void LockBufferList(ALCdevice *device) { almtx_lock(&device->BufferLock); }
|
||||
inline void UnlockBufferList(ALCdevice *device) { almtx_unlock(&device->BufferLock); }
|
||||
|
||||
inline void LockEffectList(ALCdevice *device) { almtx_lock(&device->EffectLock); }
|
||||
inline void UnlockEffectList(ALCdevice *device) { almtx_unlock(&device->EffectLock); }
|
||||
|
||||
extern ALuint CPUCapFlags;
|
||||
enum {
|
||||
CPU_CAP_SSE = 1<<0,
|
||||
CPU_CAP_SSE2 = 1<<1,
|
||||
CPU_CAP_SSE3 = 1<<2,
|
||||
CPU_CAP_SSE4_1 = 1<<3,
|
||||
CPU_CAP_NEON = 1<<4,
|
||||
};
|
||||
inline void LockFilterList(ALCdevice *device) { almtx_lock(&device->FilterLock); }
|
||||
inline void UnlockFilterList(ALCdevice *device) { almtx_unlock(&device->FilterLock); }
|
||||
|
||||
inline void LockEffectSlotList(ALCcontext *context)
|
||||
{ almtx_lock(&context->EffectSlotLock); }
|
||||
inline void UnlockEffectSlotList(ALCcontext *context)
|
||||
{ almtx_unlock(&context->EffectSlotLock); }
|
||||
|
||||
void FillCPUCaps(ALuint capfilter);
|
||||
|
||||
vector_al_string SearchDataFiles(const char *match, const char *subdir);
|
||||
|
||||
/* Small hack to use a pointer-to-array types as a normal argument type.
|
||||
* Shouldn't be used directly.
|
||||
*/
|
||||
typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
|
||||
typedef ALfloat ALfloat2[2];
|
||||
|
||||
|
||||
/* The compressor requires the following information for proper
|
||||
* initialization:
|
||||
*
|
||||
* PreGainDb - Gain applied before detection (in dB).
|
||||
* PostGainDb - Gain applied after compression (in dB).
|
||||
* SummedLink - Whether to use summed (true) or maxed (false) linking.
|
||||
* RmsSensing - Whether to use RMS (true) or Peak (false) sensing.
|
||||
* AttackTimeMin - Minimum attack time (in seconds).
|
||||
* AttackTimeMax - Maximum attack time. Automates when min != max.
|
||||
* ReleaseTimeMin - Minimum release time (in seconds).
|
||||
* ReleaseTimeMax - Maximum release time. Automates when min != max.
|
||||
* Ratio - Compression ratio (x:1). Set to 0 for true limiter.
|
||||
* ThresholdDb - Triggering threshold (in dB).
|
||||
* KneeDb - Knee width (below threshold; in dB).
|
||||
* SampleRate - Sample rate to process.
|
||||
*/
|
||||
struct Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb,
|
||||
const ALboolean SummedLink, const ALboolean RmsSensing, const ALfloat AttackTimeMin,
|
||||
const ALfloat AttackTimeMax, const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax,
|
||||
const ALfloat Ratio, const ALfloat ThresholdDb, const ALfloat KneeDb,
|
||||
const ALuint SampleRate);
|
||||
|
||||
ALuint GetCompressorSampleRate(const struct Compressor *Comp);
|
||||
|
||||
void ApplyCompression(struct Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
|
||||
ALfloat (*restrict OutBuffer)[BUFFERSIZE]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -19,8 +19,10 @@ struct ALsource;
|
||||
|
||||
|
||||
typedef struct ALbufferlistitem {
|
||||
struct ALbuffer *buffer;
|
||||
ATOMIC(struct ALbufferlistitem*) next;
|
||||
ALsizei max_samples;
|
||||
ALsizei num_buffers;
|
||||
struct ALbuffer *buffers[];
|
||||
} ALbufferlistitem;
|
||||
|
||||
|
||||
@@ -91,32 +93,22 @@ typedef struct ALsource {
|
||||
ALint SourceType;
|
||||
|
||||
/** Source state (initial, playing, paused, or stopped) */
|
||||
ATOMIC(ALenum) state;
|
||||
ALenum state;
|
||||
|
||||
/** Source Buffer Queue head. */
|
||||
RWLock queue_lock;
|
||||
ALbufferlistitem *queue;
|
||||
|
||||
ATOMIC_FLAG PropsClean;
|
||||
|
||||
/* Index into the context's Voices array. Lazily updated, only checked and
|
||||
* reset when looking up the voice.
|
||||
*/
|
||||
ALint VoiceIdx;
|
||||
|
||||
/** Self ID */
|
||||
ALuint id;
|
||||
} ALsource;
|
||||
|
||||
inline void LockSourcesRead(ALCcontext *context)
|
||||
{ LockUIntMapRead(&context->SourceMap); }
|
||||
inline void UnlockSourcesRead(ALCcontext *context)
|
||||
{ UnlockUIntMapRead(&context->SourceMap); }
|
||||
inline void LockSourcesWrite(ALCcontext *context)
|
||||
{ LockUIntMapWrite(&context->SourceMap); }
|
||||
inline void UnlockSourcesWrite(ALCcontext *context)
|
||||
{ UnlockUIntMapWrite(&context->SourceMap); }
|
||||
|
||||
inline struct ALsource *LookupSource(ALCcontext *context, ALuint id)
|
||||
{ return (struct ALsource*)LookupUIntMapKeyNoLock(&context->SourceMap, id); }
|
||||
inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id)
|
||||
{ return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); }
|
||||
|
||||
void UpdateAllSourceProps(ALCcontext *context);
|
||||
|
||||
ALvoid ReleaseALSources(ALCcontext *Context);
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef ALTHUNK_H
|
||||
#define ALTHUNK_H
|
||||
|
||||
#include "alMain.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void ThunkInit(void);
|
||||
void ThunkExit(void);
|
||||
ALenum NewThunkEntry(ALuint *index);
|
||||
void FreeThunkEntry(ALuint index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //ALTHUNK_H
|
||||
|
||||
@@ -12,28 +12,27 @@
|
||||
|
||||
#include "alMain.h"
|
||||
#include "alBuffer.h"
|
||||
#include "alFilter.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
|
||||
#include "hrtf.h"
|
||||
#include "align.h"
|
||||
#include "nfcfilter.h"
|
||||
#include "math_defs.h"
|
||||
#include "filters/defs.h"
|
||||
#include "filters/nfc.h"
|
||||
|
||||
|
||||
#define MAX_PITCH (255)
|
||||
|
||||
/* Maximum number of buffer samples before the current pos needed for resampling. */
|
||||
#define MAX_PRE_SAMPLES 12
|
||||
|
||||
/* Maximum number of buffer samples after the current pos needed for resampling. */
|
||||
#define MAX_POST_SAMPLES 12
|
||||
/* Maximum number of samples to pad on either end of a buffer for resampling.
|
||||
* Note that both the beginning and end need padding!
|
||||
*/
|
||||
#define MAX_RESAMPLE_PADDING 24
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct BSincTable;
|
||||
struct ALsource;
|
||||
struct ALbufferlistitem;
|
||||
struct ALvoice;
|
||||
@@ -53,13 +52,16 @@ enum Resampler {
|
||||
PointResampler,
|
||||
LinearResampler,
|
||||
FIR4Resampler,
|
||||
BSincResampler,
|
||||
BSinc12Resampler,
|
||||
BSinc24Resampler,
|
||||
|
||||
ResamplerMax = BSincResampler
|
||||
ResamplerMax = BSinc24Resampler
|
||||
};
|
||||
extern enum Resampler ResamplerDefault;
|
||||
|
||||
/* The number of distinct scale and phase intervals within the filter table. */
|
||||
/* The number of distinct scale and phase intervals within the bsinc filter
|
||||
* table.
|
||||
*/
|
||||
#define BSINC_SCALE_BITS 4
|
||||
#define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
|
||||
#define BSINC_PHASE_BITS 4
|
||||
@@ -71,27 +73,29 @@ extern enum Resampler ResamplerDefault;
|
||||
*/
|
||||
typedef struct BsincState {
|
||||
ALfloat sf; /* Scale interpolation factor. */
|
||||
ALuint m; /* Coefficient count. */
|
||||
ALsizei m; /* Coefficient count. */
|
||||
ALint l; /* Left coefficient offset. */
|
||||
struct {
|
||||
const ALfloat *filter; /* Filter coefficients. */
|
||||
const ALfloat *scDelta; /* Scale deltas. */
|
||||
const ALfloat *phDelta; /* Phase deltas. */
|
||||
const ALfloat *spDelta; /* Scale-phase deltas. */
|
||||
} coeffs[BSINC_PHASE_COUNT];
|
||||
/* Filter coefficients, followed by the scale, phase, and scale-phase
|
||||
* delta coefficients. Starting at phase index 0, each subsequent phase
|
||||
* index follows contiguously.
|
||||
*/
|
||||
const ALfloat *filter;
|
||||
} BsincState;
|
||||
|
||||
typedef union InterpState {
|
||||
BsincState bsinc;
|
||||
} InterpState;
|
||||
|
||||
ALboolean BsincPrepare(const ALuint increment, BsincState *state);
|
||||
|
||||
typedef const ALfloat* (*ResamplerFunc)(const InterpState *state,
|
||||
const ALfloat *restrict src, ALsizei frac, ALint increment,
|
||||
ALfloat *restrict dst, ALsizei dstlen
|
||||
);
|
||||
|
||||
void BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table);
|
||||
|
||||
extern const struct BSincTable bsinc12;
|
||||
extern const struct BSincTable bsinc24;
|
||||
|
||||
|
||||
typedef union aluVector {
|
||||
alignas(16) ALfloat v[4];
|
||||
@@ -149,10 +153,10 @@ typedef struct MixHrtfParams {
|
||||
|
||||
|
||||
typedef struct DirectParams {
|
||||
ALfilterState LowPass;
|
||||
ALfilterState HighPass;
|
||||
BiquadState LowPass;
|
||||
BiquadState HighPass;
|
||||
|
||||
NfcFilter NFCtrlFilter[MAX_AMBI_ORDER];
|
||||
NfcFilter NFCtrlFilter;
|
||||
|
||||
struct {
|
||||
HrtfParams Old;
|
||||
@@ -167,8 +171,8 @@ typedef struct DirectParams {
|
||||
} DirectParams;
|
||||
|
||||
typedef struct SendParams {
|
||||
ALfilterState LowPass;
|
||||
ALfilterState HighPass;
|
||||
BiquadState LowPass;
|
||||
BiquadState HighPass;
|
||||
|
||||
struct {
|
||||
ALfloat Current[MAX_OUTPUT_CHANNELS];
|
||||
@@ -231,16 +235,15 @@ struct ALvoiceProps {
|
||||
} Send[];
|
||||
};
|
||||
|
||||
/* If not 'fading', gain targets are used directly without fading. */
|
||||
#define VOICE_IS_FADING (1<<0)
|
||||
#define VOICE_HAS_HRTF (1<<1)
|
||||
#define VOICE_HAS_NFC (1<<2)
|
||||
#define VOICE_IS_STATIC (1<<0)
|
||||
#define VOICE_IS_FADING (1<<1) /* Fading sources use gain stepping for smooth transitions. */
|
||||
#define VOICE_HAS_HRTF (1<<2)
|
||||
#define VOICE_HAS_NFC (1<<3)
|
||||
|
||||
typedef struct ALvoice {
|
||||
struct ALvoiceProps *Props;
|
||||
|
||||
ATOMIC(struct ALvoiceProps*) Update;
|
||||
ATOMIC(struct ALvoiceProps*) FreeList;
|
||||
|
||||
ATOMIC(struct ALsource*) Source;
|
||||
ATOMIC(bool) Playing;
|
||||
@@ -277,7 +280,7 @@ typedef struct ALvoice {
|
||||
|
||||
ALuint Offset; /* Number of output samples mixed since starting. */
|
||||
|
||||
alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES];
|
||||
alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_RESAMPLE_PADDING];
|
||||
|
||||
InterpState ResampleState;
|
||||
|
||||
@@ -381,19 +384,26 @@ inline ALuint64 maxu64(ALuint64 a, ALuint64 b)
|
||||
inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
|
||||
{ return minu64(max, maxu64(min, val)); }
|
||||
|
||||
|
||||
extern alignas(16) const ALfloat bsincTab[18840];
|
||||
extern alignas(16) const ALfloat sinc4Tab[FRACTIONONE][4];
|
||||
inline size_t minz(size_t a, size_t b)
|
||||
{ return ((a > b) ? b : a); }
|
||||
inline size_t maxz(size_t a, size_t b)
|
||||
{ return ((a > b) ? a : b); }
|
||||
inline size_t clampz(size_t val, size_t min, size_t max)
|
||||
{ return minz(max, maxz(min, val)); }
|
||||
|
||||
|
||||
inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
|
||||
{
|
||||
return val1 + (val2-val1)*mu;
|
||||
}
|
||||
inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALsizei frac)
|
||||
inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu)
|
||||
{
|
||||
return sinc4Tab[frac][0]*val0 + sinc4Tab[frac][1]*val1 +
|
||||
sinc4Tab[frac][2]*val2 + sinc4Tab[frac][3]*val3;
|
||||
ALfloat mu2 = mu*mu, mu3 = mu2*mu;
|
||||
ALfloat a0 = -0.5f*mu3 + mu2 + -0.5f*mu;
|
||||
ALfloat a1 = 1.5f*mu3 + -2.5f*mu2 + 1.0f;
|
||||
ALfloat a2 = -1.5f*mu3 + 2.0f*mu2 + 0.5f*mu;
|
||||
ALfloat a3 = 0.5f*mu3 + -0.5f*mu2;
|
||||
return val1*a0 + val2*a1 + val3*a2 + val4*a3;
|
||||
}
|
||||
|
||||
|
||||
@@ -403,10 +413,10 @@ enum HrtfRequestMode {
|
||||
Hrtf_Disable = 2,
|
||||
};
|
||||
|
||||
void aluInit(void);
|
||||
|
||||
void aluInitMixer(void);
|
||||
|
||||
MixerFunc SelectMixer(void);
|
||||
RowMixerFunc SelectRowMixer(void);
|
||||
ResamplerFunc SelectResampler(enum Resampler resampler);
|
||||
|
||||
/* aluInitRenderer
|
||||
@@ -418,6 +428,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
|
||||
|
||||
void aluInitEffectPanning(struct ALeffectslot *slot);
|
||||
|
||||
void aluSelectPostProcess(ALCdevice *device);
|
||||
|
||||
/**
|
||||
* CalcDirectionCoeffs
|
||||
*
|
||||
@@ -454,35 +466,26 @@ inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread,
|
||||
*/
|
||||
void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
|
||||
|
||||
/**
|
||||
* ComputeAmbientGains
|
||||
*
|
||||
* Computes channel gains for ambient, omni-directional sounds.
|
||||
*/
|
||||
#define ComputeAmbientGains(b, g, o) do { \
|
||||
if((b).CoeffCount > 0) \
|
||||
ComputeAmbientGainsMC((b).Ambi.Coeffs, (b).NumChannels, g, o); \
|
||||
else \
|
||||
ComputeAmbientGainsBF((b).Ambi.Map, (b).NumChannels, g, o); \
|
||||
} while (0)
|
||||
void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
|
||||
void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
/**
|
||||
* ComputePanningGains
|
||||
* ComputeDryPanGains
|
||||
*
|
||||
* Computes panning gains using the given channel decoder coefficients and the
|
||||
* pre-calculated direction or angle coefficients.
|
||||
*/
|
||||
#define ComputePanningGains(b, c, g, o) do { \
|
||||
if((b).CoeffCount > 0) \
|
||||
ComputePanningGainsMC((b).Ambi.Coeffs, (b).NumChannels, (b).CoeffCount, c, g, o);\
|
||||
else \
|
||||
ComputePanningGainsBF((b).Ambi.Map, (b).NumChannels, c, g, o); \
|
||||
} while (0)
|
||||
void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
||||
{
|
||||
if(dry->CoeffCount > 0)
|
||||
ComputePanningGainsMC(dry->Ambi.Coeffs, dry->NumChannels, dry->CoeffCount,
|
||||
coeffs, ingain, gains);
|
||||
else
|
||||
ComputePanningGainsBF(dry->Ambi.Map, dry->NumChannels, coeffs, ingain, gains);
|
||||
}
|
||||
|
||||
void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
/**
|
||||
* ComputeFirstOrderGains
|
||||
*
|
||||
@@ -490,24 +493,29 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, con
|
||||
* a 1x4 'slice' of a transform matrix for the input channel, used to scale and
|
||||
* orient the sound samples.
|
||||
*/
|
||||
#define ComputeFirstOrderGains(b, m, g, o) do { \
|
||||
if((b).CoeffCount > 0) \
|
||||
ComputeFirstOrderGainsMC((b).Ambi.Coeffs, (b).NumChannels, m, g, o); \
|
||||
else \
|
||||
ComputeFirstOrderGainsBF((b).Ambi.Map, (b).NumChannels, m, g, o); \
|
||||
} while (0)
|
||||
void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
|
||||
inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
||||
{
|
||||
if(foa->CoeffCount > 0)
|
||||
ComputeFirstOrderGainsMC(foa->Ambi.Coeffs, foa->NumChannels, mtx, ingain, gains);
|
||||
else
|
||||
ComputeFirstOrderGainsBF(foa->Ambi.Map, foa->NumChannels, mtx, ingain, gains);
|
||||
}
|
||||
|
||||
|
||||
ALboolean MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo);
|
||||
ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo);
|
||||
|
||||
void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples);
|
||||
/* Caller must lock the device. */
|
||||
void aluHandleDisconnect(ALCdevice *device);
|
||||
/* Caller must lock the device, and the mixer must not be running. */
|
||||
void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3);
|
||||
|
||||
void UpdateContextProps(ALCcontext *context);
|
||||
|
||||
extern MixerFunc MixSamples;
|
||||
extern RowMixerFunc MixRowSamples;
|
||||
|
||||
extern ALfloat ConeScale;
|
||||
extern ALfloat ZScale;
|
||||
extern ALboolean OverrideReverbSpeedOfSound;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
#include "AL/al.h"
|
||||
#include "alBuffer.h"
|
||||
|
||||
void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align);
|
||||
extern const ALshort muLawDecompressionTable[256];
|
||||
extern const ALshort aLawDecompressionTable[256];
|
||||
|
||||
void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len,
|
||||
ALsizei align);
|
||||
void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len,
|
||||
ALsizei align);
|
||||
|
||||
#endif /* SAMPLE_CVT_H */
|
||||
|
||||
Reference in New Issue
Block a user