aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Alc/backends/mmdevapi.c75
-rw-r--r--Alc/bformatdec.c4
-rw-r--r--Alc/effects/reverb.c422
-rw-r--r--Alc/helpers.c35
-rw-r--r--Alc/hrtf.c80
-rw-r--r--Alc/mixer.c18
-rw-r--r--OpenAL32/Include/alMain.h10
-rw-r--r--OpenAL32/Include/alu.h2
8 files changed, 396 insertions, 250 deletions
diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c
index bcef0a5f..31092db7 100644
--- a/Alc/backends/mmdevapi.c
+++ b/Alc/backends/mmdevapi.c
@@ -52,6 +52,7 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0);
+DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 );
#define MONO SPEAKER_FRONT_CENTER
#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
@@ -67,6 +68,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x
typedef struct {
al_string name;
+ al_string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent.
WCHAR *devid;
} DevMap;
TYPEDEF_VECTOR(DevMap, vector_DevMap)
@@ -75,6 +77,7 @@ static void clear_devlist(vector_DevMap *list)
{
#define CLEAR_DEVMAP(i) do { \
AL_STRING_DEINIT((i)->name); \
+ AL_STRING_DEINIT((i)->endpoint_guid); \
free((i)->devid); \
(i)->devid = NULL; \
} while(0)
@@ -119,10 +122,11 @@ static HRESULT WaitForResponse(ThreadRequest *req)
}
-static void get_device_name(IMMDevice *device, al_string *name)
+static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_string *guid)
{
IPropertyStore *ps;
PROPVARIANT pvname;
+ PROPVARIANT pvguid;
HRESULT hr;
al_string_copy_cstr(name, DEVNAME_HEAD);
@@ -132,6 +136,7 @@ static void get_device_name(IMMDevice *device, al_string *name)
{
WARN("OpenPropertyStore failed: 0x%08lx\n", hr);
al_string_append_cstr(name, "Unknown Device Name");
+ if(guid!=NULL)al_string_copy_cstr(guid, "Unknown Device GUID");
return;
}
@@ -150,8 +155,28 @@ static void get_device_name(IMMDevice *device, al_string *name)
WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt);
al_string_append_cstr(name, "Unknown Device Name");
}
-
PropVariantClear(&pvname);
+
+ if(guid!=NULL){
+ PropVariantInit(&pvguid);
+
+ hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&PKEY_AudioEndpoint_GUID, &pvguid);
+ if(FAILED(hr))
+ {
+ WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr);
+ al_string_copy_cstr(guid, "Unknown Device GUID");
+ }
+ else if(pvguid.vt == VT_LPWSTR)
+ al_string_copy_wcstr(guid, pvguid.pwszVal);
+ else
+ {
+ WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt);
+ al_string_copy_cstr(guid, "Unknown Device GUID");
+ }
+
+ PropVariantClear(&pvguid);
+ }
+
IPropertyStore_Release(ps);
}
@@ -193,9 +218,10 @@ static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list)
AL_STRING_INIT(tmpname);
AL_STRING_INIT(entry.name);
+ AL_STRING_INIT(entry.endpoint_guid);
entry.devid = strdupW(devid);
- get_device_name(device, &tmpname);
+ get_device_name_and_guid(device, &tmpname, &entry.endpoint_guid);
while(1)
{
@@ -216,7 +242,7 @@ static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list)
count++;
}
- TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid);
+ TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.endpoint_guid), entry.devid);
VECTOR_PUSH_BACK(*list, entry);
AL_STRING_DEINIT(tmpname);
@@ -663,7 +689,6 @@ static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *
return ALC_TRUE;
}
-
static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *deviceName)
{
HRESULT hr = S_OK;
@@ -690,8 +715,23 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi
}
hr = E_FAIL;
-#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
+#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0 || \
+ al_string_cmp_cstr((i)->endpoint_guid, deviceName) == 0)
VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
+#undef MATCH_NAME
+ if(iter == VECTOR_END(PlaybackDevices))
+ {
+ int len;
+ if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, NULL, 0)) > 0)
+ {
+ WCHAR *wname = calloc(sizeof(WCHAR), len);
+ MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname, len);
+#define MATCH_NAME(i) (wcscmp((i)->devid, wname) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
+#undef MATCH_NAME
+ free(wname);
+ }
+ }
if(iter == VECTOR_END(PlaybackDevices))
WARN("Failed to find device name matching \"%s\"\n", deviceName);
else
@@ -701,7 +741,6 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi
al_string_copy(&device->DeviceName, iter->name);
hr = S_OK;
}
-#undef MATCH_NAME
}
}
@@ -758,7 +797,7 @@ static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self)
{
self->client = ptr;
if(al_string_empty(device->DeviceName))
- get_device_name(self->mmdev, &device->DeviceName);
+ get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL);
}
if(FAILED(hr))
@@ -1335,8 +1374,23 @@ static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *device
}
hr = E_FAIL;
-#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
+#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0 || \
+ al_string_cmp_cstr((i)->endpoint_guid, deviceName) == 0)
VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
+#undef MATCH_NAME
+ if(iter == VECTOR_END(CaptureDevices))
+ {
+ int len;
+ if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, NULL, 0)) > 0)
+ {
+ WCHAR *wname = calloc(sizeof(WCHAR), len);
+ MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname, len);
+#define MATCH_NAME(i) (wcscmp((i)->devid, wname) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
+#undef MATCH_NAME
+ free(wname);
+ }
+ }
if(iter == VECTOR_END(CaptureDevices))
WARN("Failed to find device name matching \"%s\"\n", deviceName);
else
@@ -1346,7 +1400,6 @@ static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *device
al_string_copy(&device->DeviceName, iter->name);
hr = S_OK;
}
-#undef MATCH_NAME
}
}
@@ -1421,7 +1474,7 @@ static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self)
{
self->client = ptr;
if(al_string_empty(device->DeviceName))
- get_device_name(self->mmdev, &device->DeviceName);
+ get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL);
}
if(FAILED(hr))
diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c
index 056eb7f5..0722c061 100644
--- a/Alc/bformatdec.c
+++ b/Alc/bformatdec.c
@@ -161,7 +161,7 @@ static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = {
static ALfloat Ambi3DEncoder[8][MAX_AMBI_COEFFS];
-static inline RowMixerFunc SelectMixer(void)
+static inline RowMixerFunc SelectRowMixer(void)
{
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
@@ -183,7 +183,7 @@ static void init_bformatdec(void)
{
ALuint i, j;
- MixMatrixRow = SelectMixer();
+ MixMatrixRow = SelectRowMixer();
for(i = 0;i < COUNTOF(Ambi3DPoints);i++)
CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, Ambi3DEncoder[i]);
diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c
index c10cd8f0..ef25c076 100644
--- a/Alc/effects/reverb.c
+++ b/Alc/effects/reverb.c
@@ -30,12 +30,23 @@
#include "alEffect.h"
#include "alFilter.h"
#include "alError.h"
+#include "mixer_defs.h"
/* This is the maximum number of samples processed for each inner loop
* iteration. */
#define MAX_UPDATE_SAMPLES 256
+
+static MixerFunc MixSamples = Mix_C;
+
+static alonce_flag mixfunc_inited = AL_ONCE_FLAG_INIT;
+static void init_mixfunc(void)
+{
+ MixSamples = SelectMixer();
+}
+
+
typedef struct DelayLine
{
// The delay lines use sample lengths that are powers of 2 to allow the
@@ -90,11 +101,8 @@ typedef struct ALreverbState {
ALuint Offset[4];
// The gain for each output channel based on 3D panning.
- // NOTE: With certain output modes, we may be rendering to the dry
- // buffer and the "real" buffer. The two combined may be using more
- // than the max output channels, so we need some extra for the real
- // output too.
- ALfloat PanGain[4][MAX_OUTPUT_CHANNELS*2];
+ ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS+2];
+ ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2];
} Early;
// Decorrelator delay line.
@@ -132,8 +140,8 @@ typedef struct ALreverbState {
ALfloat LpSample[4];
// The gain for each output channel based on 3D panning.
- // NOTE: Add some extra in case (see note about early pan).
- ALfloat PanGain[4][MAX_OUTPUT_CHANNELS*2];
+ ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS+2];
+ ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2];
} Late;
struct {
@@ -164,8 +172,8 @@ typedef struct ALreverbState {
ALuint Offset;
/* Temporary storage used when processing. */
- ALfloat ReverbSamples[MAX_UPDATE_SAMPLES][4];
- ALfloat EarlySamples[MAX_UPDATE_SAMPLES][4];
+ alignas(16) ALfloat ReverbSamples[4][MAX_UPDATE_SAMPLES];
+ alignas(16) ALfloat EarlySamples[4][MAX_UPDATE_SAMPLES];
} ALreverbState;
static ALvoid ALreverbState_Destruct(ALreverbState *State);
@@ -1130,7 +1138,7 @@ static void EAXModulation(ALreverbState *State, ALuint offset, ALfloat*restrict
// Given some input sample, this function produces four-channel outputs for the
// early reflections.
-static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4])
+static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES])
{
ALfloat d[4], v, f[4];
ALuint i;
@@ -1175,10 +1183,10 @@ static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat
/* Output the results of the junction for all four channels with a
* constant attenuation of 0.5.
*/
- out[i][0] = f[0] * 0.5f;
- out[i][1] = f[1] * 0.5f;
- out[i][2] = f[2] * 0.5f;
- out[i][3] = f[3] * 0.5f;
+ out[0][i] = f[0] * 0.5f;
+ out[1][i] = f[1] * 0.5f;
+ out[2][i] = f[2] * 0.5f;
+ out[3][i] = f[3] * 0.5f;
}
}
@@ -1216,123 +1224,140 @@ static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALflo
// Given four decorrelated input samples, this function produces four-channel
// output for the late reverb.
-static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4])
+static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES])
{
ALfloat d[4], f[4];
- ALuint i;
+ ALuint offset;
+ ALuint base, i;
// Feed the decorrelator from the energy-attenuated output of the second
// delay tap.
+ offset = State->Offset;
for(i = 0;i < todo;i++)
{
- ALuint offset = State->Offset+i;
ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) *
State->Late.DensityGain;
DelayLineIn(&State->Decorrelator, offset, sample);
+ offset++;
}
- for(i = 0;i < todo;i++)
+ offset = State->Offset;
+ for(base = 0;base < todo;)
{
- ALuint offset = State->Offset+i;
+ ALfloat tmp[MAX_UPDATE_SAMPLES/4][4];
+ ALuint tmp_todo = minu(todo, MAX_UPDATE_SAMPLES/4);
- /* Obtain four decorrelated input samples. */
- f[0] = DelayLineOut(&State->Decorrelator, offset);
- f[1] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[0]);
- f[2] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[1]);
- f[3] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[2]);
+ for(i = 0;i < tmp_todo;i++)
+ {
+ /* Obtain four decorrelated input samples. */
+ f[0] = DelayLineOut(&State->Decorrelator, offset);
+ f[1] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[0]);
+ f[2] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[1]);
+ f[3] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[2]);
+
+ /* Add the decayed results of the cyclical delay lines, then pass
+ * the results through the low-pass filters.
+ */
+ f[0] += DelayLineOut(&State->Late.Delay[0], offset-State->Late.Offset[0]) * State->Late.Coeff[0];
+ f[1] += DelayLineOut(&State->Late.Delay[1], offset-State->Late.Offset[1]) * State->Late.Coeff[1];
+ f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2];
+ f[3] += DelayLineOut(&State->Late.Delay[3], offset-State->Late.Offset[3]) * State->Late.Coeff[3];
+
+ /* This is where the feed-back cycles from line 0 to 1 to 3 to 2
+ * and back to 0.
+ */
+ d[0] = LateLowPassInOut(State, 2, f[2]);
+ d[1] = LateLowPassInOut(State, 0, f[0]);
+ d[2] = LateLowPassInOut(State, 3, f[3]);
+ d[3] = LateLowPassInOut(State, 1, f[1]);
+
+ /* To help increase diffusion, run each line through an all-pass
+ * filter. When there is no diffusion, the shortest all-pass filter
+ * will feed the shortest delay line.
+ */
+ d[0] = LateAllPassInOut(State, offset, 0, d[0]);
+ d[1] = LateAllPassInOut(State, offset, 1, d[1]);
+ d[2] = LateAllPassInOut(State, offset, 2, d[2]);
+ d[3] = LateAllPassInOut(State, offset, 3, d[3]);
+
+ /* Late reverb is done with a modified feed-back delay network (FDN)
+ * topology. Four input lines are each fed through their own all-pass
+ * filter and then into the mixing matrix. The four outputs of the
+ * mixing matrix are then cycled back to the inputs. Each output feeds
+ * a different input to form a circlular feed cycle.
+ *
+ * The mixing matrix used is a 4D skew-symmetric rotation matrix
+ * derived using a single unitary rotational parameter:
+ *
+ * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
+ * [ -a, d, c, -b ]
+ * [ -b, -c, d, a ]
+ * [ -c, b, -a, d ]
+ *
+ * The rotation is constructed from the effect's diffusion parameter,
+ * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
+ * with differing signs, and d is the coefficient x. The matrix is
+ * thus:
+ *
+ * [ x, y, -y, y ] n = sqrt(matrix_order - 1)
+ * [ -y, x, y, y ] t = diffusion_parameter * atan(n)
+ * [ y, -y, x, y ] x = cos(t)
+ * [ -y, -y, -y, x ] y = sin(t) / n
+ *
+ * To reduce the number of multiplies, the x coefficient is applied
+ * with the cyclical delay line coefficients. Thus only the y
+ * coefficient is applied when mixing, and is modified to be: y / x.
+ */
+ f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3]));
+ f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3]));
+ f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3]));
+ f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] ));
+
+ /* Re-feed the cyclical delay lines. */
+ DelayLineIn(&State->Late.Delay[0], offset, f[0]);
+ DelayLineIn(&State->Late.Delay[1], offset, f[1]);
+ DelayLineIn(&State->Late.Delay[2], offset, f[2]);
+ DelayLineIn(&State->Late.Delay[3], offset, f[3]);
+ offset++;
+
+ /* Output the results of the matrix for all four channels,
+ * attenuated by the late reverb gain (which is attenuated by the
+ * 'x' mix coefficient).
+ */
+ tmp[i][0] = State->Late.Gain * f[0];
+ tmp[i][1] = State->Late.Gain * f[1];
+ tmp[i][2] = State->Late.Gain * f[2];
+ tmp[i][3] = State->Late.Gain * f[3];
+ }
- /* Add the decayed results of the cyclical delay lines, then pass the
- * results through the low-pass filters.
- */
- f[0] += DelayLineOut(&State->Late.Delay[0], offset-State->Late.Offset[0]) * State->Late.Coeff[0];
- f[1] += DelayLineOut(&State->Late.Delay[1], offset-State->Late.Offset[1]) * State->Late.Coeff[1];
- f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2];
- f[3] += DelayLineOut(&State->Late.Delay[3], offset-State->Late.Offset[3]) * State->Late.Coeff[3];
-
- // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and
- // back to 0.
- d[0] = LateLowPassInOut(State, 2, f[2]);
- d[1] = LateLowPassInOut(State, 0, f[0]);
- d[2] = LateLowPassInOut(State, 3, f[3]);
- d[3] = LateLowPassInOut(State, 1, f[1]);
-
- // To help increase diffusion, run each line through an all-pass filter.
- // When there is no diffusion, the shortest all-pass filter will feed
- // the shortest delay line.
- d[0] = LateAllPassInOut(State, offset, 0, d[0]);
- d[1] = LateAllPassInOut(State, offset, 1, d[1]);
- d[2] = LateAllPassInOut(State, offset, 2, d[2]);
- d[3] = LateAllPassInOut(State, offset, 3, d[3]);
-
- /* Late reverb is done with a modified feed-back delay network (FDN)
- * topology. Four input lines are each fed through their own all-pass
- * filter and then into the mixing matrix. The four outputs of the
- * mixing matrix are then cycled back to the inputs. Each output feeds
- * a different input to form a circlular feed cycle.
- *
- * The mixing matrix used is a 4D skew-symmetric rotation matrix
- * derived using a single unitary rotational parameter:
- *
- * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
- * [ -a, d, c, -b ]
- * [ -b, -c, d, a ]
- * [ -c, b, -a, d ]
- *
- * The rotation is constructed from the effect's diffusion parameter,
- * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
- * with differing signs, and d is the coefficient x. The matrix is
- * thus:
- *
- * [ x, y, -y, y ] n = sqrt(matrix_order - 1)
- * [ -y, x, y, y ] t = diffusion_parameter * atan(n)
- * [ y, -y, x, y ] x = cos(t)
- * [ -y, -y, -y, x ] y = sin(t) / n
- *
- * To reduce the number of multiplies, the x coefficient is applied
- * with the cyclical delay line coefficients. Thus only the y
- * coefficient is applied when mixing, and is modified to be: y / x.
- */
- f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3]));
- f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3]));
- f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3]));
- f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] ));
-
- // Output the results of the matrix for all four channels, attenuated by
- // the late reverb gain (which is attenuated by the 'x' mix coefficient).
- out[i][0] = State->Late.Gain * f[0];
- out[i][1] = State->Late.Gain * f[1];
- out[i][2] = State->Late.Gain * f[2];
- out[i][3] = State->Late.Gain * f[3];
-
- // Re-feed the cyclical delay lines.
- DelayLineIn(&State->Late.Delay[0], offset, f[0]);
- DelayLineIn(&State->Late.Delay[1], offset, f[1]);
- DelayLineIn(&State->Late.Delay[2], offset, f[2]);
- DelayLineIn(&State->Late.Delay[3], offset, f[3]);
+ /* Deinterlace to output */
+ for(i = 0;i < tmp_todo;i++) out[0][base+i] = tmp[i][0];
+ for(i = 0;i < tmp_todo;i++) out[1][base+i] = tmp[i][1];
+ for(i = 0;i < tmp_todo;i++) out[2][base+i] = tmp[i][2];
+ for(i = 0;i < tmp_todo;i++) out[3][base+i] = tmp[i][3];
+
+ base += tmp_todo;
}
}
// Given an input sample, this function mixes echo into the four-channel late
// reverb.
-static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[4])
+static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[MAX_UPDATE_SAMPLES])
{
- ALfloat out, feed;
+ ALfloat out[MAX_UPDATE_SAMPLES];
+ ALfloat feed;
+ ALuint offset;
ALuint i;
+ offset = State->Offset;
for(i = 0;i < todo;i++)
{
- ALuint offset = State->Offset+i;
-
// Get the latest attenuated echo sample for output.
feed = DelayLineOut(&State->Echo.Delay, offset-State->Echo.Offset) *
State->Echo.Coeff;
- // Mix the output into the late reverb channels.
- out = State->Echo.MixCoeff * feed;
- late[i][0] += out;
- late[i][1] += out;
- late[i][2] += out;
- late[i][3] += out;
+ // Write the output.
+ out[i] = State->Echo.MixCoeff * feed;
// Mix the energy-attenuated input with the output and pass it through
// the echo low-pass filter.
@@ -1348,19 +1373,26 @@ static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restri
// Feed the delay with the mixed and filtered sample.
DelayLineIn(&State->Echo.Delay, offset, feed);
+ offset++;
}
+
+ // Mix the output into the late reverb channels.
+ for(i = 0;i < todo;i++) late[0][i] += out[i];
+ for(i = 0;i < todo;i++) late[1][i] += out[i];
+ for(i = 0;i < todo;i++) late[2][i] += out[i];
+ for(i = 0;i < todo;i++) late[3][i] += out[i];
}
// Perform the non-EAX reverb pass on a given input sample, resulting in
// four-channel output.
-static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4])
+static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES])
{
ALuint i;
// Low-pass filter the incoming samples (use the early buffer as temp storage).
ALfilterState_process(&State->LpFilter, &early[0][0], input, todo);
for(i = 0;i < todo;i++)
- DelayLineIn(&State->Delay, State->Offset+i, early[i>>2][i&3]);
+ DelayLineIn(&State->Delay, State->Offset+i, early[0][i]);
// Calculate the early reflection from the first delay tap.
EarlyReflection(State, todo, early);
@@ -1374,25 +1406,19 @@ static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *
// Perform the EAX reverb pass on a given input sample, resulting in four-
// channel output.
-static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4])
+static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES])
{
ALuint i;
/* Perform any modulation on the input (use the early buffer as temp storage). */
EAXModulation(State, State->Offset, &early[0][0], input, todo);
/* Band-pass the incoming samples */
- ALfilterState_process(&State->LpFilter,
- &early[MAX_UPDATE_SAMPLES/4][0], &early[0][0], todo
- );
- ALfilterState_process(&State->HpFilter,
- &early[MAX_UPDATE_SAMPLES*2/4][0], &early[MAX_UPDATE_SAMPLES/4][0], todo
- );
+ ALfilterState_process(&State->LpFilter, &early[1][0], &early[0][0], todo);
+ ALfilterState_process(&State->HpFilter, &early[2][0], &early[1][0], todo);
// Feed the initial delay line.
for(i = 0;i < todo;i++)
- DelayLineIn(&State->Delay, State->Offset+i,
- early[(MAX_UPDATE_SAMPLES*2/4)+(i>>2)][i&3]
- );
+ DelayLineIn(&State->Delay, State->Offset+i, early[2][i]);
// Calculate the early reflection from the first delay tap.
EarlyReflection(State, todo, early);
@@ -1407,107 +1433,117 @@ static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloa
State->Offset += todo;
}
+static void DoMix(const ALfloat *restrict src, ALfloat (*dst)[BUFFERSIZE], ALuint num_chans,
+ const ALfloat *restrict target_gains, ALfloat *restrict current_gains,
+ ALfloat delta, ALuint offset, ALuint total_rem, ALuint todo)
+{
+ MixGains gains[MAX_OUTPUT_CHANNELS];
+ ALuint c;
+
+ for(c = 0;c < num_chans;c++)
+ {
+ ALfloat diff;
+ gains[c].Target = target_gains[c];
+ gains[c].Current = current_gains[c];
+ diff = gains[c].Target - gains[c].Current;
+ if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD)
+ gains[c].Step = diff * delta;
+ else
+ {
+ gains[c].Current = gains[c].Target;
+ gains[c].Step = 0.0f;
+ }
+ }
+
+ MixSamples(src, num_chans, dst, gains, total_rem, offset, todo);
+
+ for(c = 0;c < num_chans;c++)
+ current_gains[c] = gains[c].Current;
+}
+
static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
- ALfloat (*restrict early)[4] = State->EarlySamples;
- ALfloat (*restrict late)[4] = State->ReverbSamples;
- ALuint index, c, i, l;
- ALfloat gain;
+ ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples;
+ ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples;
+ ALuint base, c;
/* Process reverb for these samples. */
- for(index = 0;index < SamplesToDo;)
+ for(base = 0;base < SamplesToDo;)
{
- ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES);
+ const ALfloat delta = 1.0f / (ALfloat)(SamplesToDo-base);
+ ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES);
- VerbPass(State, todo, &SamplesIn[index], early, late);
+ VerbPass(State, todo, &SamplesIn[base], early, late);
- for(l = 0;l < 4;l++)
+ for(c = 0;c < 4;c++)
{
- for(c = 0;c < NumChannels;c++)
- {
- gain = State->Early.PanGain[l][c];
- if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
- {
- for(i = 0;i < todo;i++)
- SamplesOut[c][index+i] += gain*early[i][l];
- }
- gain = State->Late.PanGain[l][c];
- if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
- {
- for(i = 0;i < todo;i++)
- SamplesOut[c][index+i] += gain*late[i][l];
- }
- }
- for(c = 0;c < State->ExtraChannels;c++)
- {
- gain = State->Early.PanGain[l][NumChannels+c];
- if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
- {
- for(i = 0;i < todo;i++)
- State->ExtraOut[c][index+i] += gain*early[i][l];
- }
- gain = State->Late.PanGain[l][NumChannels+c];
- if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
- {
- for(i = 0;i < todo;i++)
- State->ExtraOut[c][index+i] += gain*late[i][l];
- }
- }
+ DoMix(early[c], SamplesOut, NumChannels, State->Early.PanGain[c],
+ State->Early.CurrentGain[c], delta, base, SamplesToDo-base, todo
+ );
+ if(State->ExtraChannels > 0)
+ DoMix(early[c], SamplesOut, State->ExtraChannels,
+ State->Early.PanGain[c]+NumChannels,
+ State->Early.CurrentGain[c]+NumChannels, delta, base,
+ SamplesToDo-base, todo
+ );
+ }
+ for(c = 0;c < 4;c++)
+ {
+ DoMix(late[c], SamplesOut, NumChannels, State->Late.PanGain[c],
+ State->Late.CurrentGain[c], delta, base, SamplesToDo, todo
+ );
+ if(State->ExtraChannels > 0)
+ DoMix(late[c], SamplesOut, State->ExtraChannels,
+ State->Late.PanGain[c]+NumChannels,
+ State->Late.CurrentGain[c]+NumChannels, delta, base,
+ SamplesToDo-base, todo
+ );
}
- index += todo;
+ base += todo;
}
}
static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
- ALfloat (*restrict early)[4] = State->EarlySamples;
- ALfloat (*restrict late)[4] = State->ReverbSamples;
- ALuint index, c, i, l;
- ALfloat gain;
+ ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples;
+ ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples;
+ ALuint base, c;
/* Process reverb for these samples. */
- for(index = 0;index < SamplesToDo;)
+ for(base = 0;base < SamplesToDo;)
{
- ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES);
+ const ALfloat delta = 1.0f / (ALfloat)(SamplesToDo-base);
+ ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES);
- EAXVerbPass(State, todo, &SamplesIn[index], early, late);
+ EAXVerbPass(State, todo, &SamplesIn[base], early, late);
- for(l = 0;l < 4;l++)
+ for(c = 0;c < 4;c++)
+ {
+ DoMix(early[c], SamplesOut, NumChannels, State->Early.PanGain[c],
+ State->Early.CurrentGain[c], delta, base, SamplesToDo-base, todo
+ );
+ if(State->ExtraChannels > 0)
+ DoMix(early[c], SamplesOut, State->ExtraChannels,
+ State->Early.PanGain[c]+NumChannels,
+ State->Early.CurrentGain[c]+NumChannels, delta, base,
+ SamplesToDo-base, todo
+ );
+ }
+ for(c = 0;c < 4;c++)
{
- for(c = 0;c < NumChannels;c++)
- {
- gain = State->Early.PanGain[l][c];
- if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
- {
- for(i = 0;i < todo;i++)
- SamplesOut[c][index+i] += gain*early[i][l];
- }
- gain = State->Late.PanGain[l][c];
- if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
- {
- for(i = 0;i < todo;i++)
- SamplesOut[c][index+i] += gain*late[i][l];
- }
- }
- for(c = 0;c < State->ExtraChannels;c++)
- {
- gain = State->Early.PanGain[l][NumChannels+c];
- if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
- {
- for(i = 0;i < todo;i++)
- State->ExtraOut[c][index+i] += gain*early[i][l];
- }
- gain = State->Late.PanGain[l][NumChannels+c];
- if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
- {
- for(i = 0;i < todo;i++)
- State->ExtraOut[c][index+i] += gain*late[i][l];
- }
- }
+ DoMix(late[c], SamplesOut, NumChannels, State->Late.PanGain[c],
+ State->Late.CurrentGain[c], delta, base, SamplesToDo, todo
+ );
+ if(State->ExtraChannels > 0)
+ DoMix(late[c], SamplesOut, State->ExtraChannels,
+ State->Late.PanGain[c]+NumChannels,
+ State->Late.CurrentGain[c]+NumChannels, delta, base,
+ SamplesToDo-base, todo
+ );
}
- index += todo;
+ base += todo;
}
}
@@ -1528,6 +1564,8 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f
{
ALreverbState *state;
+ alcall_once(&mixfunc_inited, init_mixfunc);
+
NEW_OBJ0(state, ALreverbState)();
if(!state) return NULL;
diff --git a/Alc/helpers.c b/Alc/helpers.c
index 9d7d564f..26ed535a 100644
--- a/Alc/helpers.c
+++ b/Alc/helpers.c
@@ -32,6 +32,7 @@
#include <time.h>
#include <errno.h>
#include <stdarg.h>
+#include <ctype.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
@@ -65,6 +66,7 @@ DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x1
#include <propkeydef.h>
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0);
+DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 );
#endif
#endif
#endif /* AL_NO_UID_DEFS */
@@ -231,8 +233,37 @@ void FillCPUCaps(ALuint capfilter)
#endif
#endif
#ifdef HAVE_NEON
- /* Assume Neon support if compiled with it */
- caps |= CPU_CAP_NEON;
+ FILE *file = fopen("/proc/cpuinfo", "rt");
+ if(!file)
+ ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n");
+ else
+ {
+ char buf[256];
+ while(fgets(buf, sizeof(buf), file) != NULL)
+ {
+ char *str;
+
+ if(strncmp(buf, "Features\t:", 10) != 0)
+ continue;
+
+ TRACE("Got features string:%s\n", buf+10);
+
+ str = buf;
+ while((str=strstr(str, "neon")) != NULL)
+ {
+ if(isspace(*(str-1)) && (str[4] == 0 || isspace(str[4])))
+ {
+ caps |= CPU_CAP_NEON;
+ break;
+ }
+ str++;
+ }
+ break;
+ }
+
+ fclose(file);
+ file = NULL;
+ }
#endif
TRACE("Extensions:%s%s%s%s%s%s\n",
diff --git a/Alc/hrtf.c b/Alc/hrtf.c
index 16db0c33..d7cd6bad 100644
--- a/Alc/hrtf.c
+++ b/Alc/hrtf.c
@@ -178,25 +178,37 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][
static const struct {
ALfloat elevation;
ALfloat azimuth;
- } CubePoints[8] = {
+ } Ambi3DPoints[14] = {
+ { DEG2RAD( 90.0f), DEG2RAD( 0.0f) },
{ DEG2RAD( 35.0f), DEG2RAD( -45.0f) },
{ DEG2RAD( 35.0f), DEG2RAD( 45.0f) },
- { DEG2RAD( 35.0f), DEG2RAD(-135.0f) },
{ DEG2RAD( 35.0f), DEG2RAD( 135.0f) },
+ { DEG2RAD( 35.0f), DEG2RAD(-135.0f) },
+ { DEG2RAD( 0.0f), DEG2RAD( 0.0f) },
+ { DEG2RAD( 0.0f), DEG2RAD( 90.0f) },
+ { DEG2RAD( 0.0f), DEG2RAD( 180.0f) },
+ { DEG2RAD( 0.0f), DEG2RAD( -90.0f) },
{ DEG2RAD(-35.0f), DEG2RAD( -45.0f) },
{ DEG2RAD(-35.0f), DEG2RAD( 45.0f) },
- { DEG2RAD(-35.0f), DEG2RAD(-135.0f) },
{ DEG2RAD(-35.0f), DEG2RAD( 135.0f) },
+ { DEG2RAD(-35.0f), DEG2RAD(-135.0f) },
+ { DEG2RAD(-90.0f), DEG2RAD( 0.0f) },
};
- static const ALfloat CubeMatrix[8][2][MAX_AMBI_COEFFS] = {
- { { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } },
- { { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } },
- { { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } },
- { { 0.25f, -0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, 0.125f, -0.125f } },
- { { 0.25f, 0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, -0.125f, 0.125f } },
- { { 0.25f, -0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, -0.125f, 0.125f } },
- { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } },
- { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } },
+ static const ALfloat Ambi3DMatrix[14][2][MAX_AMBI_COEFFS] = {
+ { { 0.18898176f, 0.000000000f, 0.188982460f, 0.000000000f }, { 0.0714283915f, 0.0000000000f, 0.1237180798f, 0.0000000000f } },
+ { { 0.18898176f, 0.109109004f, 0.109109004f, 0.109109004f }, { 0.0714283915f, 0.0714286206f, 0.0714286206f, 0.0714286206f } },
+ { { 0.18898176f, -0.109109004f, 0.109109004f, 0.109109004f }, { 0.0714283915f, -0.0714286206f, 0.0714286206f, 0.0714286206f } },
+ { { 0.18898176f, -0.109109004f, 0.109109004f, -0.109109004f }, { 0.0714283915f, -0.0714286206f, 0.0714286206f, -0.0714286206f } },
+ { { 0.18898176f, 0.109109004f, 0.109109004f, -0.109109004f }, { 0.0714283915f, 0.0714286206f, 0.0714286206f, -0.0714286206f } },
+ { { 0.18898176f, 0.000000000f, 0.000000000f, 0.188982460f }, { 0.0714283915f, 0.0000000000f, 0.0000000000f, 0.1237180798f } },
+ { { 0.18898176f, -0.188982460f, 0.000000000f, 0.000000000f }, { 0.0714283915f, -0.1237180798f, 0.0000000000f, 0.0000000000f } },
+ { { 0.18898176f, 0.000000000f, 0.000000000f, -0.188982460f }, { 0.0714283915f, 0.0000000000f, 0.0000000000f, -0.1237180798f } },
+ { { 0.18898176f, 0.188982460f, 0.000000000f, 0.000000000f }, { 0.0714283915f, 0.1237180798f, 0.0000000000f, 0.0000000000f } },
+ { { 0.18898176f, 0.109109004f, -0.109109004f, 0.109109004f }, { 0.0714283915f, 0.0714286206f, -0.0714286206f, 0.0714286206f } },
+ { { 0.18898176f, -0.109109004f, -0.109109004f, 0.109109004f }, { 0.0714283915f, -0.0714286206f, -0.0714286206f, 0.0714286206f } },
+ { { 0.18898176f, -0.109109004f, -0.109109004f, -0.109109004f }, { 0.0714283915f, -0.0714286206f, -0.0714286206f, -0.0714286206f } },
+ { { 0.18898176f, 0.109109004f, -0.109109004f, -0.109109004f }, { 0.0714283915f, 0.0714286206f, -0.0714286206f, -0.0714286206f } },
+ { { 0.18898176f, 0.000000000f, -0.188982460f, 0.000000000f }, { 0.0714283915f, 0.0000000000f, -0.1237180798f, 0.0000000000f } },
};
/* Change this to 2 for dual-band HRTF processing. May require a higher quality
* band-splitter, or better calculation of the new IR length to deal with the
@@ -205,21 +217,21 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][
#define NUM_BANDS 1
BandSplitter splitter;
ALfloat temps[3][HRIR_LENGTH];
- ALuint lidx[8], ridx[8];
+ ALuint lidx[14], ridx[14];
ALuint min_delay = HRTF_HISTORY_LENGTH;
ALuint max_length = 0;
ALuint i, j, c, b;
assert(NumChannels == 4);
- for(c = 0;c < 8;c++)
+ for(c = 0;c < COUNTOF(Ambi3DPoints);c++)
{
ALuint evidx, azidx;
ALuint evoffset;
ALuint azcount;
/* Calculate elevation index. */
- evidx = (ALuint)floorf((F_PI_2 + CubePoints[c].elevation) *
+ evidx = (ALuint)floorf((F_PI_2 + Ambi3DPoints[c].elevation) *
(Hrtf->evCount-1)/F_PI + 0.5f);
evidx = minu(evidx, Hrtf->evCount-1);
@@ -227,7 +239,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][
evoffset = Hrtf->evOffset[evidx];
/* Calculate azimuth index for this elevation. */
- azidx = (ALuint)floorf((F_TAU+CubePoints[c].azimuth) *
+ azidx = (ALuint)floorf((F_TAU+Ambi3DPoints[c].azimuth) *
azcount/F_TAU + 0.5f) % azcount;
/* Calculate indices for left and right channels. */
@@ -239,7 +251,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][
memset(temps, 0, sizeof(temps));
bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate);
- for(c = 0;c < 8;c++)
+ for(c = 0;c < COUNTOF(Ambi3DMatrix);c++)
{
const ALshort *fir;
ALuint delay;
@@ -268,7 +280,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][
{
ALuint k = 0;
for(j = delay;j < HRIR_LENGTH;++j)
- coeffs[i][j][0] += temps[b][k++] * CubeMatrix[c][b][i];
+ coeffs[i][j][0] += temps[b][k++] * Ambi3DMatrix[c][b][i];
}
}
max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH));
@@ -297,7 +309,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][
{
ALuint k = 0;
for(j = delay;j < HRIR_LENGTH;++j)
- coeffs[i][j][1] += temps[b][k++] * CubeMatrix[c][b][i];
+ coeffs[i][j][1] += temps[b][k++] * Ambi3DMatrix[c][b][i];
}
}
max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH));
@@ -468,6 +480,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str
{
size_t total = sizeof(struct Hrtf);
total += sizeof(azCount[0])*evCount;
+ total = (total+1)&~1; /* Align for (u)short fields */
total += sizeof(evOffset[0])*evCount;
total += sizeof(coeffs[0])*irSize*irCount;
total += sizeof(delays[0])*irCount;
@@ -483,14 +496,18 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str
if(!failed)
{
+ char *base = (char*)Hrtf;
+ uintptr_t offset = sizeof(*Hrtf);
+
Hrtf->sampleRate = rate;
Hrtf->irSize = irSize;
Hrtf->evCount = evCount;
- Hrtf->azCount = ((ALubyte*)(Hrtf+1));
- Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount));
- Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount));
- Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount));
- Hrtf->filename = ((char*)(Hrtf->delays + irCount));
+ Hrtf->azCount = ((ALubyte*)(base + offset)); offset += evCount*sizeof(Hrtf->azCount[0]);
+ offset = (offset+1)&~1; /* Align for (u)short fields */
+ Hrtf->evOffset = ((ALushort*)(base + offset)); offset += evCount*sizeof(Hrtf->evOffset[0]);
+ Hrtf->coeffs = ((ALshort*)(base + offset)); offset += irSize*irCount*sizeof(Hrtf->coeffs[0]);
+ Hrtf->delays = ((ALubyte*)(base + offset)); offset += irCount*sizeof(Hrtf->delays[0]);
+ Hrtf->filename = ((char*)(base + offset));
Hrtf->next = NULL;
memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount);
@@ -644,6 +661,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str
{
size_t total = sizeof(struct Hrtf);
total += sizeof(azCount[0])*evCount;
+ total = (total+1)&~1; /* Align for (u)short fields */
total += sizeof(evOffset[0])*evCount;
total += sizeof(coeffs[0])*irSize*irCount;
total += sizeof(delays[0])*irCount;
@@ -659,14 +677,18 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str
if(!failed)
{
+ char *base = (char*)Hrtf;
+ uintptr_t offset = sizeof(*Hrtf);
+
Hrtf->sampleRate = rate;
Hrtf->irSize = irSize;
Hrtf->evCount = evCount;
- Hrtf->azCount = ((ALubyte*)(Hrtf+1));
- Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount));
- Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount));
- Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount));
- Hrtf->filename = ((char*)(Hrtf->delays + irCount));
+ Hrtf->azCount = ((ALubyte*)(base + offset)); offset += evCount*sizeof(Hrtf->azCount[0]);
+ offset = (offset+1)&~1; /* Align for (u)short fields */
+ Hrtf->evOffset = ((ALushort*)(base + offset)); offset += evCount*sizeof(Hrtf->evOffset[0]);
+ Hrtf->coeffs = ((ALshort*)(base + offset)); offset += irSize*irCount*sizeof(Hrtf->coeffs[0]);
+ Hrtf->delays = ((ALubyte*)(base + offset)); offset += irCount*sizeof(Hrtf->delays[0]);
+ Hrtf->filename = ((char*)(base + offset));
Hrtf->next = NULL;
memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount);
diff --git a/Alc/mixer.c b/Alc/mixer.c
index bbf70153..2736920e 100644
--- a/Alc/mixer.c
+++ b/Alc/mixer.c
@@ -61,36 +61,36 @@ static_assert(MAX_PRE_SAMPLES >= 3, "MAX_PRE_SAMPLES must be at least 3!");
static_assert(MAX_POST_SAMPLES >= 4, "MAX_POST_SAMPLES must be at least 4!");
-static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
static MixerFunc MixSamples = Mix_C;
+static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
static ResamplerFunc ResampleSamples = Resample_point32_C;
-static inline HrtfMixerFunc SelectHrtfMixer(void)
+MixerFunc SelectMixer(void)
{
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
- return MixHrtf_SSE;
+ return Mix_SSE;
#endif
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
- return MixHrtf_Neon;
+ return Mix_Neon;
#endif
- return MixHrtf_C;
+ return Mix_C;
}
-static inline MixerFunc SelectMixer(void)
+static inline HrtfMixerFunc SelectHrtfMixer(void)
{
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
- return Mix_SSE;
+ return MixHrtf_SSE;
#endif
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
- return Mix_Neon;
+ return MixHrtf_Neon;
#endif
- return Mix_C;
+ return MixHrtf_C;
}
static inline ResamplerFunc SelectResampler(enum Resampler resampler)
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index d7975cea..ac537978 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -699,17 +699,17 @@ struct ALCdevice_struct
};
// 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. */
diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h
index d236c58b..3d1a4986 100644
--- a/OpenAL32/Include/alu.h
+++ b/OpenAL32/Include/alu.h
@@ -264,6 +264,8 @@ enum HrtfRequestMode {
void aluInitMixer(void);
+MixerFunc SelectMixer(void);
+
/* aluInitRenderer
*
* Set up the appropriate panning method and mixing method given the device