Update OpenAL Soft to 1.18.2

This commit is contained in:
Alex Szpakowski
2017-12-10 22:34:10 -04:00
parent 75e0077566
commit b160006eb1
152 changed files with 33572 additions and 15363 deletions
@@ -4,6 +4,7 @@
#include "alMain.h"
#include "alEffect.h"
#include "atomic.h"
#include "align.h"
#ifdef __cplusplus
@@ -14,15 +15,22 @@ 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 ALCdevice *device, 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);
};
@@ -30,8 +38,8 @@ struct ALeffectStateVtable {
#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 ALCdevice*, 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)); } \
\
@@ -64,36 +72,101 @@ static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable =
}
#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;
ATOMIC(struct ALeffectslotProps*) FreeList;
struct {
ALfloat Gain;
ALboolean AuxSendAuto;
ALenum EffectType;
ALeffectState *EffectState;
ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */
ALfloat DecayTime;
ALfloat DecayHFRatio;
ALboolean DecayHFLimit;
ALfloat AirAbsorptionGainHF;
} Params;
/* Self ID */
ALuint 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
* * Channel 2 is OpenAL Y
* * Channel 3 is OpenAL -Z
* 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
* first-order device output (FOAOut).
*/
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*)LookupUIntMapKey(&context->EffectSlotMap, id); }
{ return (struct ALeffectslot*)LookupUIntMapKeyNoLock(&context->EffectSlotMap, id); }
inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id)
{ return (struct ALeffectslot*)RemoveUIntMapKey(&context->EffectSlotMap, id); }
{ return (struct ALeffectslot*)RemoveUIntMapKeyNoLock(&context->EffectSlotMap, id); }
ALenum InitEffectSlot(ALeffectslot *slot);
void DeinitEffectSlot(ALeffectslot *slot);
void UpdateEffectSlotProps(ALeffectslot *slot);
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);
+31 -23
View File
@@ -17,28 +17,26 @@ enum UserFmtType {
UserFmtUInt = AL_UNSIGNED_INT_SOFT,
UserFmtFloat = AL_FLOAT_SOFT,
UserFmtDouble = AL_DOUBLE_SOFT,
UserFmtByte3 = AL_BYTE3_SOFT,
UserFmtUByte3 = AL_UNSIGNED_BYTE3_SOFT,
UserFmtMulaw,
UserFmtAlaw,
UserFmtMulaw = AL_MULAW_SOFT,
UserFmtAlaw = 0x10000000,
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 */
UserFmtBFormat3D, /* WXYZ */
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 */
};
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);
}
@@ -63,9 +61,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);
}
@@ -80,14 +78,15 @@ typedef struct ALbuffer {
enum FmtChannels FmtChannels;
enum FmtType FmtType;
ALuint BytesAlloc;
enum UserFmtChannels OriginalChannels;
enum UserFmtType OriginalType;
ALsizei OriginalSize;
ALsizei OriginalAlign;
ALsizei LoopStart;
ALsizei LoopEnd;
ALsizei LoopStart;
ALsizei LoopEnd;
ATOMIC(ALsizei) UnpackAlign;
ATOMIC(ALsizei) PackAlign;
@@ -106,10 +105,19 @@ 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*)LookupUIntMapKey(&device->BufferMap, id); }
{ return (struct ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); }
inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id)
{ return (struct ALbuffer*)RemoveUIntMapKey(&device->BufferMap, id); }
{ return (struct ALbuffer*)RemoveUIntMapKeyNoLock(&device->BufferMap, id); }
ALvoid ReleaseALBuffers(ALCdevice *device);
+21 -21
View File
@@ -10,17 +10,16 @@ extern "C" {
struct ALeffect;
enum {
EAXREVERB = 0,
REVERB,
AUTOWAH,
CHORUS,
COMPRESSOR,
DISTORTION,
ECHO,
EQUALIZER,
FLANGER,
MODULATOR,
DEDICATED,
AL__EAXREVERB = 0,
AL__REVERB,
AL__CHORUS,
AL__COMPRESSOR,
AL__DISTORTION,
AL__ECHO,
AL__EQUALIZER,
AL__FLANGER,
AL__MODULATOR,
AL__DEDICATED,
MAX_EFFECTS
};
@@ -51,7 +50,6 @@ const struct ALeffectVtable T##_vtable = { \
extern const struct ALeffectVtable ALeaxreverb_vtable;
extern const struct ALeffectVtable ALreverb_vtable;
extern const struct ALeffectVtable ALautowah_vtable;
extern const struct ALeffectVtable ALchorus_vtable;
extern const struct ALeffectVtable ALcompressor_vtable;
extern const struct ALeffectVtable ALdistortion_vtable;
@@ -93,13 +91,6 @@ typedef union ALeffectProps {
ALfloat LFReference;
} Reverb;
struct {
ALfloat AttackTime;
ALfloat ReleaseTime;
ALfloat PeakGain;
ALfloat Resonance;
} Autowah;
struct {
ALint Waveform;
ALint Phase;
@@ -176,10 +167,19 @@ typedef struct ALeffect {
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*)LookupUIntMapKey(&device->EffectMap, id); }
{ return (struct ALeffect*)LookupUIntMapKeyNoLock(&device->EffectMap, id); }
inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id)
{ return (struct ALeffect*)RemoveUIntMapKey(&device->EffectMap, id); }
{ return (struct ALeffect*)RemoveUIntMapKeyNoLock(&device->EffectMap, id); }
inline ALboolean IsReverbEffect(ALenum type)
{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; }
+22 -23
View File
@@ -42,13 +42,11 @@ typedef enum ALfilterType {
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) */
ALfloat b1, b2; /* Transfer function coefficients "b" (b0 is input_gain) */
ALfloat input_gain;
void (*process)(struct ALfilterState *self, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples);
} ALfilterState;
#define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__))
/* 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.
@@ -79,26 +77,18 @@ inline void ALfilterState_clear(ALfilterState *filter)
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ);
inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample)
inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src)
{
ALfloat outsmp;
outsmp = filter->input_gain * sample +
filter->b1 * filter->x[0] +
filter->b2 * filter->x[1] -
filter->a1 * filter->y[0] -
filter->a2 * filter->y[1];
filter->x[1] = filter->x[0];
filter->x[0] = sample;
filter->y[1] = filter->y[0];
filter->y[0] = outsmp;
return outsmp;
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 *src, ALuint numsamples);
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples);
inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples)
inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples)
{
if(numsamples >= 2)
{
@@ -151,10 +141,19 @@ typedef struct ALfilter {
#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*)LookupUIntMapKey(&device->FilterMap, id); }
{ return (struct ALfilter*)LookupUIntMapKeyNoLock(&device->FilterMap, id); }
inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id)
{ return (struct ALfilter*)RemoveUIntMapKey(&device->FilterMap, id); }
{ return (struct ALfilter*)RemoveUIntMapKeyNoLock(&device->FilterMap, id); }
ALvoid ReleaseALFilters(ALCdevice *device);
+44 -7
View File
@@ -8,20 +8,57 @@
extern "C" {
#endif
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;
};
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;
ALfloat MetersPerUnit;
/* 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 {
aluMatrixd Matrix;
aluMatrixf Matrix;
aluVector Velocity;
ALfloat Gain;
ALfloat MetersPerUnit;
ALfloat DopplerFactor;
ALfloat SpeedOfSound;
ALboolean SourceDistanceModel;
enum DistanceModel DistanceModel;
} Params;
} ALlistener;
void UpdateListenerProps(ALCcontext *context);
#ifdef __cplusplus
}
#endif
+499 -155
View File
@@ -3,6 +3,7 @@
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <assert.h>
#include <math.h>
@@ -20,6 +21,124 @@
#include "AL/alc.h"
#include "AL/alext.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"
@@ -30,24 +149,59 @@
#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);
#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; \
})
#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
@@ -81,13 +235,17 @@ typedef ALuint64SOFT ALuint64;
#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
@@ -119,7 +277,7 @@ static const union {
} EndianTest = { 1 };
#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1)
#define COUNTOF(x) (sizeof((x))/sizeof((x)[0]))
#define COUNTOF(x) (sizeof(x) / sizeof(0[x]))
#define DERIVE_FROM_TYPE(t) t t##_parent
@@ -208,6 +366,12 @@ static void T##_Delete(void *ptr) { al_free(ptr); }
{ \
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
@@ -215,6 +379,8 @@ extern "C" {
#endif
struct Hrtf;
struct HrtfEntry;
struct Compressor;
#define DEFAULT_OUTPUT_RATE (44100)
@@ -236,6 +402,31 @@ inline ALuint NextPowerOf2(ALuint value)
return value+1;
}
/** 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);
}
/* 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)
@@ -252,45 +443,12 @@ inline ALint fastf2i(ALfloat 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); }
enum DevProbe {
ALL_DEVICE_PROBE,
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;
@@ -317,10 +475,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,23 +524,37 @@ 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 */
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
};
extern const struct EffectList {
const char *name;
@@ -378,25 +571,57 @@ 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;
#define HRTF_HISTORY_BITS (6)
#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
#define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1)
#define HRIR_BITS (7)
#define HRIR_LENGTH (1<<HRIR_BITS)
#define HRIR_MASK (HRIR_LENGTH-1)
typedef struct HrtfState {
alignas(16) ALfloat History[HRTF_HISTORY_LENGTH];
alignas(16) ALfloat Values[HRIR_LENGTH][2];
@@ -404,18 +629,43 @@ typedef struct HrtfState {
typedef struct HrtfParams {
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2];
ALuint Delay[2];
ALint DelayStep[2];
ALsizei Delay[2];
ALfloat Gain;
} HrtfParams;
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;
struct HrtfEntry *hrtf;
} EnumeratedHrtf;
TYPEDEF_VECTOR(EnumeratedHrtf, vector_EnumeratedHrtf)
/* 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
{
@@ -424,25 +674,31 @@ struct ALCdevice_struct
ALCboolean 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;
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;
@@ -453,27 +709,31 @@ struct ALCdevice_struct
// 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;
/* HRTF state and info */
DirectHrtfState *Hrtf;
al_string HrtfName;
struct Hrtf *HrtfHandle;
vector_EnumeratedHrtf HrtfList;
ALCenum HrtfStatus;
// Stereo-to-binaural filter
/* 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;
@@ -481,9 +741,55 @@ struct ALCdevice_struct
alignas(16) ALfloat SourceData[BUFFERSIZE];
alignas(16) ALfloat ResampledData[BUFFERSIZE];
alignas(16) ALfloat FilteredData[BUFFERSIZE];
alignas(16) ALfloat NFCtrlData[BUFFERSIZE];
/* Dry path buffer mix. */
alignas(16) ALfloat (*DryBuffer)[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;
/* 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;
/* "Real" output, which will be written to the device buffer. May alias the
* dry buffer.
*/
struct {
enum Channel ChannelName[MAX_OUTPUT_CHANNELS];
ALfloat (*Buffer)[BUFFERSIZE];
ALsizei NumChannels;
} RealOut;
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 +798,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[];
};
// 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,8 +832,7 @@ struct ALCdevice_struct
#define RECORD_THREAD_NAME "alsoft-record"
struct ALCcontext_struct
{
struct ALCcontext_struct {
RefCount ref;
struct ALlistener *Listener;
@@ -544,28 +842,39 @@ struct ALCcontext_struct
ATOMIC(ALenum) LastError;
ATOMIC(ALenum) UpdateSources;
enum DistanceModel DistanceModel;
ALboolean SourceDistanceModel;
volatile enum DistanceModel DistanceModel;
volatile ALboolean SourceDistanceModel;
ALfloat DopplerFactor;
ALfloat DopplerVelocity;
ALfloat SpeedOfSound;
ATOMIC(ALenum) DeferUpdates;
volatile ALfloat DopplerFactor;
volatile ALfloat DopplerVelocity;
volatile ALfloat SpeedOfSound;
volatile ALenum DeferUpdates;
RWLock PropLock;
struct ALvoice *Voices;
/* 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;
struct ALvoice **Voices;
ALsizei VoiceCount;
ALsizei MaxVoices;
VECTOR(struct ALeffectslot*) ActiveAuxSlots;
ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots;
/* Default effect slot */
struct ALeffectslot *DefaultSlot;
ALCdevice *Device;
const ALCchar *ExtensionList;
ALCcontext *volatile next;
/* Memory space used by the listener */
/* Memory space used by the listener (and possibly default effect slot) */
alignas(16) ALCbyte _listener_mem[];
};
@@ -574,6 +883,8 @@ ALCcontext *GetContextRef(void);
void ALCcontext_IncRef(ALCcontext *context);
void ALCcontext_DecRef(ALCcontext *context);
void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends);
void AppendAllDevicesList(const ALCchar *name);
void AppendCaptureDeviceList(const ALCchar *name);
@@ -583,21 +894,13 @@ 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 *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);
#ifdef _WIN32
int round_mode;
#endif
#else
int state;
#endif
@@ -607,15 +910,19 @@ typedef struct {
} 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 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;
@@ -651,26 +958,26 @@ 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.
* Returns the index for the given 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;
}
#define GetChannelIdxByName(x, c) GetChannelIndex((x).ChannelName, (c))
extern FILE *LogFile;
@@ -681,6 +988,13 @@ void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FOR
#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,
@@ -698,16 +1012,19 @@ extern enum LogLevel LogLevel;
#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)
@@ -725,15 +1042,42 @@ enum {
void FillCPUCaps(ALuint capfilter);
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. */
/* 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
+70 -90
View File
@@ -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" {
@@ -17,95 +20,48 @@ struct ALsource;
typedef struct ALbufferlistitem {
struct ALbuffer *buffer;
struct ALbufferlistitem *volatile next;
struct ALbufferlistitem *volatile prev;
ATOMIC(struct ALbufferlistitem*) next;
} 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;
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;
volatile ALboolean DryGainHFAuto;
volatile ALboolean WetGainAuto;
volatile ALboolean WetGainHFAuto;
volatile ALfloat OuterGainHF;
ALboolean DryGainHFAuto;
ALboolean WetGainAuto;
ALboolean WetGainHFAuto;
ALfloat OuterGainHF;
volatile ALfloat AirAbsorptionFactor;
volatile ALfloat RoomRolloffFactor;
volatile ALfloat DopplerFactor;
ALfloat AirAbsorptionFactor;
ALfloat RoomRolloffFactor;
ALfloat DopplerFactor;
volatile ALfloat Radius;
/**
* Last user-specified offset, and the offset type (bytes, samples, or
* seconds).
/* NOTE: Stereo pan angles are specified in radians, counter-clockwise
* rather than clockwise.
*/
ALdouble Offset;
ALenum OffsetType;
ALfloat StereoPan[2];
/** 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.
*/
ALuint position;
ALuint position_fraction;
/** Source Buffer Queue info. */
ATOMIC(ALbufferlistitem*) queue;
ATOMIC(ALbufferlistitem*) current_buffer;
RWLock queue_lock;
/** Current buffer sample info. */
ALuint NumChannels;
ALuint SampleSize;
ALfloat Radius;
/** Direct filter and auxiliary send info. */
struct {
@@ -122,22 +78,46 @@ typedef struct ALsource {
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Send[MAX_SENDS];
} *Send;
/** Source needs to update its mixing parameters. */
ATOMIC(ALenum) NeedsUpdate;
/**
* 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) */
ATOMIC(ALenum) state;
/** Source Buffer Queue head. */
RWLock queue_lock;
ALbufferlistitem *queue;
ATOMIC_FLAG PropsClean;
/** 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); }
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); }
ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state);
ALboolean ApplyOffset(ALsource *Source);
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);
+295 -109
View File
@@ -13,9 +13,11 @@
#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"
@@ -33,9 +35,30 @@ extern "C" {
#endif
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
};
enum Resampler {
PointResampler,
LinearResampler,
FIR4Resampler,
BSincResampler,
ResamplerMax = BSincResampler
};
extern enum Resampler ResamplerDefault;
/* The number of distinct scale and phase intervals within the filter table. */
#define BSINC_SCALE_BITS 4
#define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
@@ -58,6 +81,17 @@ typedef struct BsincState {
} coeffs[BSINC_PHASE_COUNT];
} 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
);
typedef union aluVector {
alignas(16) ALfloat v[4];
@@ -75,6 +109,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 +132,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 +140,200 @@ 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;
ALfilterState LowPass;
ALfilterState 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[MAX_AMBI_ORDER];
struct {
enum ActiveFilters ActiveType;
ALfilterState LowPass;
ALfilterState HighPass;
} Filters[MAX_INPUT_CHANNELS];
struct {
HrtfParams Params;
HrtfParams Old;
HrtfParams Target;
HrtfState State;
} Hrtf[MAX_INPUT_CHANNELS];
MixGains Gains[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
} Hrtf;
struct {
ALfloat Current[MAX_OUTPUT_CHANNELS];
ALfloat Target[MAX_OUTPUT_CHANNELS];
} Gains;
} DirectParams;
typedef struct SendParams {
ALfloat (*OutBuffer)[BUFFERSIZE];
ALboolean Moving;
ALuint Counter;
ALfilterState LowPass;
ALfilterState 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;
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);
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[];
};
/* 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)
typedef struct ALvoice {
struct ALvoiceProps *Props;
ATOMIC(struct ALvoiceProps*) Update;
ATOMIC(struct ALvoiceProps*) FreeList;
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;
/** 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_PRE_SAMPLES];
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)
@@ -246,79 +382,129 @@ 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];
extern alignas(16) const ALfloat sinc4Tab[FRACTIONONE][4];
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)
inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALsizei 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)
{
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;
return sinc4Tab[frac][0]*val0 + sinc4Tab[frac][1]*val1 +
sinc4Tab[frac][2]*val2 + sinc4Tab[frac][3]*val3;
}
enum HrtfRequestMode {
Hrtf_Default = 0,
Hrtf_Enable = 1,
Hrtf_Disable = 2,
};
void aluInitMixer(void);
ALvoid aluInitPanning(ALCdevice *Device);
MixerFunc SelectMixer(void);
RowMixerFunc SelectRowMixer(void);
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);
/**
* ComputeDirectionalGains
* CalcDirectionCoeffs
*
* Sets channel gains based on a direction. The direction must be a 3-component
* vector no longer than 1 unit.
* Calculates ambisonic coefficients based on a direction vector. The vector
* must be normalized (unit length), and the spread is the angular width of the
* sound (0...tau).
*/
void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
/**
* ComputeAngleGains
* CalcAngleCoeffs
*
* 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 azimuth and elevation. The
* azimuth and elevation parameters are in radians, going right and up
* respectively.
*/
void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
{
ALfloat dir[3] = {
sinf(azimuth) * cosf(elevation),
sinf(elevation),
-cosf(azimuth) * cosf(elevation)
};
CalcDirectionCoeffs(dir, spread, coeffs);
}
/**
* CalcAnglePairwiseCoeffs
*
* Calculates ambisonic coefficients based on azimuth and elevation. The
* azimuth and elevation parameters are in radians, going right and up
* respectively. This pairwise variant warps the result such that +30 azimuth
* is full right, and -30 azimuth is full left.
*/
void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
/**
* ComputeAmbientGains
*
* Sets channel gains for ambient, omni-directional sounds.
* Computes channel gains for ambient, omni-directional sounds.
*/
void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
#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]);
/**
* ComputeBFormatGains
* ComputePanningGains
*
* 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.
* Computes panning gains using the given channel decoder coefficients and the
* pre-calculated direction or angle coefficients.
*/
void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
#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]);
/**
* ComputeFirstOrderGains
*
* Sets channel gains for a first-order ambisonics input channel. The matrix is
* 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]);
ALvoid UpdateContextSources(ALCcontext *context);
ALboolean MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, 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);
ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo);
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples);
/* Caller must lock the device. */
ALvoid aluHandleDisconnect(ALCdevice *device);
void aluHandleDisconnect(ALCdevice *device);
extern ALfloat ConeScale;
extern ALfloat ZScale;
+5 -36
View File
@@ -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" */