diff options
-rw-r--r-- | Alc/backends/mmdevapi.c | 75 | ||||
-rw-r--r-- | Alc/bformatdec.c | 4 | ||||
-rw-r--r-- | Alc/effects/reverb.c | 422 | ||||
-rw-r--r-- | Alc/helpers.c | 35 | ||||
-rw-r--r-- | Alc/hrtf.c | 80 | ||||
-rw-r--r-- | Alc/mixer.c | 18 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 10 | ||||
-rw-r--r-- | OpenAL32/Include/alu.h | 2 |
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", @@ -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 |