diff options
Diffstat (limited to 'OpenAL32/Include')
-rw-r--r-- | OpenAL32/Include/alAuxEffectSlot.h | 148 | ||||
-rw-r--r-- | OpenAL32/Include/alBuffer.h | 93 | ||||
-rw-r--r-- | OpenAL32/Include/alEffect.h | 77 | ||||
-rw-r--r-- | OpenAL32/Include/alError.h | 20 | ||||
-rw-r--r-- | OpenAL32/Include/alFilter.h | 134 | ||||
-rw-r--r-- | OpenAL32/Include/alListener.h | 52 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 1015 | ||||
-rw-r--r-- | OpenAL32/Include/alSource.h | 162 | ||||
-rw-r--r-- | OpenAL32/Include/alThunk.h | 20 | ||||
-rw-r--r-- | OpenAL32/Include/alu.h | 454 | ||||
-rw-r--r-- | OpenAL32/Include/bs2b.h | 41 | ||||
-rw-r--r-- | OpenAL32/Include/sample_cvt.h | 8 |
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 */ |