diff options
-rw-r--r-- | Alc/backends/mmdevapi.c | 75 | ||||
-rw-r--r-- | Alc/bformatdec.c | 4 | ||||
-rw-r--r-- | Alc/effects/equalizer.c | 4 | ||||
-rw-r--r-- | Alc/effects/modulator.c | 1 | ||||
-rw-r--r-- | Alc/effects/reverb.c | 480 | ||||
-rw-r--r-- | Alc/helpers.c | 37 | ||||
-rw-r--r-- | Alc/hrtf.c | 88 | ||||
-rw-r--r-- | Alc/mixer.c | 18 | ||||
-rw-r--r-- | CMakeLists.txt | 28 | ||||
-rw-r--r-- | OpenAL32/Include/alFilter.h | 5 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 10 | ||||
-rw-r--r-- | OpenAL32/Include/alu.h | 4 | ||||
-rw-r--r-- | OpenAL32/alFilter.c | 2 | ||||
-rw-r--r-- | appveyor.yml | 14 | ||||
-rw-r--r-- | common/threads.c | 32 | ||||
-rw-r--r-- | examples/alffplay.c | 15 | ||||
-rw-r--r-- | examples/alhrtf.c | 34 | ||||
-rw-r--r-- | examples/allatency.c | 11 | ||||
-rw-r--r-- | examples/alreverb.c | 11 | ||||
-rw-r--r-- | examples/alstream.c | 9 | ||||
-rw-r--r-- | examples/altonegen.c | 28 | ||||
-rw-r--r-- | examples/common/alhelpers.c | 30 | ||||
-rw-r--r-- | examples/common/alhelpers.h | 2 | ||||
-rw-r--r-- | utils/openal-info.c | 65 |
24 files changed, 644 insertions, 363 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/equalizer.c b/Alc/effects/equalizer.c index 61932ffb..1a63b418 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -151,7 +151,6 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[0][i].b0 = state->filter[0][0].b0; state->filter[0][i].b1 = state->filter[0][0].b1; state->filter[0][i].b2 = state->filter[0][0].b2; - state->filter[0][i].process = state->filter[0][0].process; } gain = props->Equalizer.Mid1Gain; @@ -168,7 +167,6 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[1][i].b0 = state->filter[1][0].b0; state->filter[1][i].b1 = state->filter[1][0].b1; state->filter[1][i].b2 = state->filter[1][0].b2; - state->filter[1][i].process = state->filter[1][0].process; } gain = props->Equalizer.Mid2Gain; @@ -185,7 +183,6 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[2][i].b0 = state->filter[2][0].b0; state->filter[2][i].b1 = state->filter[2][0].b1; state->filter[2][i].b2 = state->filter[2][0].b2; - state->filter[2][i].process = state->filter[2][0].process; } gain = sqrtf(props->Equalizer.HighGain); @@ -200,7 +197,6 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[3][i].b0 = state->filter[3][0].b0; state->filter[3][i].b1 = state->filter[3][0].b1; state->filter[3][i].b2 = state->filter[3][0].b2; - state->filter[3][i].process = state->filter[3][0].process; } } diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 5ca37f4f..247cdf61 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -142,7 +142,6 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * state->Filter[i].b0 = a; state->Filter[i].b1 = -a; state->Filter[i].b2 = 0.0f; - state->Filter[i].process = ALfilterState_processC; } STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer; diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index c10cd8f0..c9397b67 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 @@ -77,11 +88,16 @@ typedef struct ALreverbState { ALfloat Filter; } Mod; // EAX only - // Initial effect delay. + /* Core delay line (early reflections and late reverb tap from this). */ DelayLine Delay; - // The tap points for the initial delay. First tap goes to early - // reflections, the last to late reverb. + /* The tap points for the initial delay. First tap goes to early + * reflections, second to late reverb. + */ ALuint DelayTap[2]; + /* There are actually 4 decorrelator taps, but the first occurs at the late + * reverb tap. + */ + ALuint DecoTap[3]; struct { // Early reflections are done with 4 delay lines. @@ -90,19 +106,10 @@ 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. - DelayLine Decorrelator; - // There are actually 4 decorrelator taps, but the first occurs at the - // initial sample. - ALuint DecoTap[3]; - struct { // Output gain for late reverb. ALfloat Gain; @@ -132,8 +139,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 +171,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); @@ -205,6 +212,9 @@ static void ALreverbState_Construct(ALreverbState *state) state->Delay.Line = NULL; state->DelayTap[0] = 0; state->DelayTap[1] = 0; + state->DecoTap[0] = 0; + state->DecoTap[1] = 0; + state->DecoTap[2] = 0; for(index = 0;index < 4;index++) { @@ -214,12 +224,6 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.Offset[index] = 0; } - state->Decorrelator.Mask = 0; - state->Decorrelator.Line = NULL; - state->DecoTap[0] = 0; - state->DecoTap[1] = 0; - state->DecoTap[2] = 0; - state->Late.Gain = 0.0f; state->Late.DensityGain = 0.0f; state->Late.ApFeedCoeff = 0.0f; @@ -399,11 +403,15 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) totalSamples += CalcLineLength(length, totalSamples, frequency, 1, &State->Mod.Delay); - // The initial delay is the sum of the reflections and late reverb - // delays. This must include space for storing a loop update to feed the - // early reflections, decorrelator, and echo. + /* The initial delay is the sum of the reflections and late reverb delays. + * The decorrelator length is calculated from the lowest reverb density (a + * parameter value of 1). This must include space for storing a loop + * update. + */ length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + AL_EAXREVERB_MAX_LATE_REVERB_DELAY; + length += (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * + LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, &State->Delay); @@ -412,14 +420,6 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, frequency, 0, &State->Early.Delay[index]); - // The decorrelator line is calculated from the lowest reverb density (a - // parameter value of 1). This must include space for storing a loop update - // to feed the late reverb. - length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * - LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); - totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, - &State->Decorrelator); - // The late all-pass lines. for(index = 0;index < 4;index++) totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, @@ -454,7 +454,6 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) // Update all delays to reflect the new sample buffer. RealizeLineOffset(State->SampleBuffer, &State->Delay); - RealizeLineOffset(State->SampleBuffer, &State->Decorrelator); for(index = 0;index < 4;index++) { RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]); @@ -689,7 +688,7 @@ static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbStat { length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); - State->DecoTap[index] = fastf2u(length * frequency); + State->DecoTap[index] = fastf2u(length * frequency) + State->DelayTap[1]; } } @@ -1015,12 +1014,12 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, frequency, State); - // Update the early lines. - UpdateEarlyLines(props->Reverb.LateReverbDelay, State); - // Update the decorrelator. UpdateDecorrelator(props->Reverb.Density, frequency, State); + // Update the early lines. + UpdateEarlyLines(props->Reverb.LateReverbDelay, State); + // Get the mixing matrix coefficients (x and y). CalcMatrixCoeffs(props->Reverb.Diffusion, &x, &y); // Then divide x into y to simplify the matrix calculation. @@ -1130,7 +1129,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 +1174,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 +1215,129 @@ 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. - for(i = 0;i < todo;i++) + offset = State->Offset; + for(base = 0;base < todo;) { - ALuint offset = State->Offset+i; - ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * - State->Late.DensityGain; - DelayLineIn(&State->Decorrelator, offset, sample); - } + ALfloat tmp[MAX_UPDATE_SAMPLES/4][4]; + ALuint tmp_todo = minu(todo, MAX_UPDATE_SAMPLES/4); - for(i = 0;i < todo;i++) - { - ALuint offset = State->Offset+i; + for(i = 0;i < tmp_todo;i++) + { + /* Obtain four decorrelated input samples. */ + f[0] = DelayLineOut(&State->Delay, offset-State->DelayTap[1]) * State->Late.DensityGain; + f[1] = DelayLineOut(&State->Delay, offset-State->DecoTap[0]) * State->Late.DensityGain; + f[2] = DelayLineOut(&State->Delay, offset-State->DecoTap[1]) * State->Late.DensityGain; + f[3] = DelayLineOut(&State->Delay, offset-State->DecoTap[2]) * State->Late.DensityGain; + + /* 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]; + } - /* 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]); + /* 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]; - /* 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]); + 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 +1353,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 +1386,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 +1413,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++) + { + 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], State->ExtraOut, 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], State->ExtraOut, 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++) { - 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], State->ExtraOut, 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], State->ExtraOut, State->ExtraChannels, + State->Late.PanGain[c]+NumChannels, + State->Late.CurrentGain[c]+NumChannels, delta, base, + SamplesToDo-base, todo + ); } - index += todo; + base += todo; } } @@ -1528,6 +1544,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..d4b44ced 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", @@ -695,7 +726,7 @@ al_string GetProcPath(void) if(len <= 0) { free(pathname); - ERR("Failed to link %s: %s\n", fname, strerror(errno)); + WARN("Failed to readlink %s: %s\n", fname, strerror(errno)); return ret; } @@ -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.071428392f, 0.000000000f, 0.071428392f, 0.000000000f }, { 0.0269973975f, 0.0000000000f, 0.0467610443f, 0.0000000000f } }, + { { 0.071428392f, 0.041239332f, 0.041239332f, 0.041239332f }, { 0.0269973975f, 0.0269973975f, 0.0269973975f, 0.0269973975f } }, + { { 0.071428392f, -0.041239332f, 0.041239332f, 0.041239332f }, { 0.0269973975f, -0.0269973975f, 0.0269973975f, 0.0269973975f } }, + { { 0.071428392f, -0.041239332f, 0.041239332f, -0.041239332f }, { 0.0269973975f, -0.0269973975f, 0.0269973975f, -0.0269973975f } }, + { { 0.071428392f, 0.041239332f, 0.041239332f, -0.041239332f }, { 0.0269973975f, 0.0269973975f, 0.0269973975f, -0.0269973975f } }, + { { 0.071428392f, 0.000000000f, 0.000000000f, 0.071428392f }, { 0.0269973975f, 0.0000000000f, 0.0000000000f, 0.0467610443f } }, + { { 0.071428392f, -0.071428392f, 0.000000000f, 0.000000000f }, { 0.0269973975f, -0.0467610443f, 0.0000000000f, 0.0000000000f } }, + { { 0.071428392f, 0.000000000f, 0.000000000f, -0.071428392f }, { 0.0269973975f, 0.0000000000f, 0.0000000000f, -0.0467610443f } }, + { { 0.071428392f, 0.071428392f, 0.000000000f, 0.000000000f }, { 0.0269973975f, 0.0467610443f, 0.0000000000f, 0.0000000000f } }, + { { 0.071428392f, 0.041239332f, -0.041239332f, 0.041239332f }, { 0.0269973975f, 0.0269973975f, -0.0269973975f, 0.0269973975f } }, + { { 0.071428392f, -0.041239332f, -0.041239332f, 0.041239332f }, { 0.0269973975f, -0.0269973975f, -0.0269973975f, 0.0269973975f } }, + { { 0.071428392f, -0.041239332f, -0.041239332f, -0.041239332f }, { 0.0269973975f, -0.0269973975f, -0.0269973975f, -0.0269973975f } }, + { { 0.071428392f, 0.041239332f, -0.041239332f, -0.041239332f }, { 0.0269973975f, 0.0269973975f, -0.0269973975f, -0.0269973975f } }, + { { 0.071428392f, 0.000000000f, -0.071428392f, 0.000000000f }, { 0.0269973975f, 0.0000000000f, -0.0467610443f, 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); @@ -1029,16 +1051,16 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) /* Find the preferred HRTF and move it to the front of the list. */ #define FIND_ENTRY(i) (al_string_cmp_cstr((i)->name, defaulthrtf) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, list, FIND_ENTRY); - if(iter != VECTOR_END(list) && iter != VECTOR_BEGIN(list)) +#undef FIND_ENTRY + if(iter == VECTOR_END(list)) + WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); + else if(iter != VECTOR_BEGIN(list)) { HrtfEntry entry = *iter; memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0), (iter-VECTOR_BEGIN(list))*sizeof(HrtfEntry)); VECTOR_ELEM(list,0) = entry; } - else - WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); -#undef FIND_ENTRY } return list; 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/CMakeLists.txt b/CMakeLists.txt index f85fb14f..d4b4b626 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,6 +178,23 @@ IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") ENDIF() +# Some systems may need libatomic for C11 atomic functions to work +SET(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) +SET(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES} atomic) +CHECK_C_SOURCE_COMPILES("#include <stdatomic.h> +int _Atomic foo = ATOMIC_VAR_INIT(0); +int main() +{ + return atomic_fetch_add(&foo, 2); +}" +HAVE_LIBATOMIC) +IF(NOT HAVE_LIBATOMIC) + SET(CMAKE_REQUIRED_LIBRARIES "${OLD_REQUIRED_LIBRARIES}") +ELSE() + SET(EXTRA_LIBS atomic ${EXTRA_LIBS}) +ENDIF() +UNSET(OLD_REQUIRED_LIBRARIES) + # Check if we have C99 variable length arrays CHECK_C_SOURCE_COMPILES( "int main(int argc, char *argv[]) @@ -220,8 +237,10 @@ HAVE_C11_ALIGNAS) CHECK_C_SOURCE_COMPILES( "#include <stdatomic.h> const int _Atomic foo = ATOMIC_VAR_INIT(~0); + int _Atomic bar = ATOMIC_VAR_INIT(0); int main() { + atomic_fetch_add(&bar, 2); return atomic_load(&foo); }" HAVE_C11_ATOMIC) @@ -371,6 +390,7 @@ SET(SSE_SWITCH "") SET(SSE2_SWITCH "") SET(SSE3_SWITCH "") SET(SSE4_1_SWITCH "") +SET(FPU_NEON_SWITCH "") IF(NOT MSVC) CHECK_C_COMPILER_FLAG(-msse HAVE_MSSE_SWITCH) IF(HAVE_MSSE_SWITCH) @@ -388,6 +408,10 @@ IF(NOT MSVC) IF(HAVE_MSSE4_1_SWITCH) SET(SSE4_1_SWITCH "-msse4.1") ENDIF() + CHECK_C_COMPILER_FLAG(-mfpu=neon HAVE_MFPU_NEON_SWITCH) + IF(HAVE_MFPU_NEON_SWITCH) + SET(FPU_NEON_SWITCH "-mfpu=neon") + ENDIF() ENDIF() CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(printf, 1, 2))); @@ -773,6 +797,10 @@ IF(HAVE_ARM_NEON_H) IF(ALSOFT_CPUEXT_NEON) SET(HAVE_NEON 1) SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_neon.c) + IF(FPU_NEON_SWITCH) + SET_SOURCE_FILES_PROPERTIES(Alc/mixer_neon.c PROPERTIES + COMPILE_FLAGS "${FPU_NEON_SWITCH}") + ENDIF() SET(CPU_EXTS "${CPU_EXTS}, Neon") ENDIF() ENDIF() diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index a74cd211..1f7095bc 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -44,10 +44,9 @@ typedef struct ALfilterState { ALfloat y[2]; /* History of two last output samples */ ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ ALfloat b0, b1, b2; /* Transfer function coefficients "b" */ - - void (*process)(struct ALfilterState *self, ALfloat *restrict dst, const ALfloat *restrict 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. 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..29cb00fb 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -79,7 +79,7 @@ inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALf typedef union aluMatrixf { alignas(16) ALfloat m[4][4]; } aluMatrixf; -const aluMatrixf IdentityMatrixf; +extern const aluMatrixf IdentityMatrixf; inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3) @@ -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 diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index fa3496c9..c675d344 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -431,8 +431,6 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g filter->b0 = b[0] / a[0]; filter->b1 = b[1] / a[0]; filter->b2 = b[2] / a[0]; - - filter->process = ALfilterState_processC; } diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..4010f2ea --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,14 @@ +version: 1.17.2.{build} + +environment: + matrix: + - GEN: "Visual Studio 14 2015" + CFG: Release + - GEN: "Visual Studio 14 2015 Win64" + CFG: Release + +build_script: + - cd build + - cmake .. -G"%GEN%" + - cmake --build . --config %CFG% --clean-first + diff --git a/common/threads.c b/common/threads.c index 24a197a4..0a019d03 100644 --- a/common/threads.c +++ b/common/threads.c @@ -55,7 +55,7 @@ extern inline int altss_set(altss_t tss_id, void *val); #endif -#define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */ +#define THREAD_STACK_SIZE (2*1024*1024) /* 2MB */ #ifdef _WIN32 @@ -531,6 +531,8 @@ int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) { thread_cntr *cntr; pthread_attr_t attr; + size_t stackmult = 1; + int err; cntr = malloc(sizeof(*cntr)); if(!cntr) return althrd_nomem; @@ -540,7 +542,8 @@ int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) free(cntr); return althrd_error; } - if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE) != 0) +retry_stacksize: + if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE*stackmult) != 0) { pthread_attr_destroy(&attr); free(cntr); @@ -549,15 +552,30 @@ int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) cntr->func = func; cntr->arg = arg; - if(pthread_create(thr, &attr, althrd_starter, cntr) != 0) + if((err=pthread_create(thr, &attr, althrd_starter, cntr)) == 0) { pthread_attr_destroy(&attr); - free(cntr); - return althrd_error; + return althrd_success; } - pthread_attr_destroy(&attr); - return althrd_success; + if(err == EINVAL) + { + /* If an invalid stack size, try increasing it (limit x4, 8MB). */ + if(stackmult < 4) + { + stackmult *= 2; + goto retry_stacksize; + } + /* If still nothing, try defaults and hope they're good enough. */ + if(pthread_create(thr, NULL, althrd_starter, cntr) == 0) + { + pthread_attr_destroy(&attr); + return althrd_success; + } + } + pthread_attr_destroy(&attr); + free(cntr); + return althrd_error; } int althrd_detach(althrd_t thr) diff --git a/examples/alffplay.c b/examples/alffplay.c index 2d38216f..e95dede6 100644 --- a/examples/alffplay.c +++ b/examples/alffplay.c @@ -1332,6 +1332,7 @@ int main(int argc, char *argv[]) SDL_Renderer *renderer; ALCdevice *device; ALCcontext *context; + int fileidx; if(argc < 2) { @@ -1389,7 +1390,17 @@ int main(int argc, char *argv[]) SDL_RenderPresent(renderer); /* Open an audio device */ - device = alcOpenDevice(NULL); + fileidx = 1; + device = NULL; + if(argc > 3 && strcmp(argv[1], "-device") == 0) + { + fileidx = 3; + device = alcOpenDevice(argv[2]); + if(!device) + fprintf(stderr, "OpenAL: could not open \"%s\" - trying default\n", argv[2]); + } + if(!device) + device = alcOpenDevice(NULL); if(!device) { fprintf(stderr, "OpenAL: could not open device - exiting\n"); @@ -1429,7 +1440,7 @@ int main(int argc, char *argv[]) movState = av_mallocz(sizeof(MovieState)); - av_strlcpy(movState->filename, argv[1], sizeof(movState->filename)); + av_strlcpy(movState->filename, argv[fileidx], sizeof(movState->filename)); packet_queue_init(&movState->audio.q); packet_queue_init(&movState->video.q); diff --git a/examples/alhrtf.c b/examples/alhrtf.c index 23d60a74..3964a7c6 100644 --- a/examples/alhrtf.c +++ b/examples/alhrtf.c @@ -122,28 +122,18 @@ int main(int argc, char **argv) ALdouble angle; ALenum state; - /* Print out usage if no file was specified */ - if(argc < 2 || (strcmp(argv[1], "-hrtf") == 0 && argc < 4)) + /* Print out usage if no arguments were specified */ + if(argc < 2) { - fprintf(stderr, "Usage: %s [-hrtf <name>] <soundfile>\n", argv[0]); + fprintf(stderr, "Usage: %s [-device <name>] [-hrtf <name>] <soundfile>\n", argv[0]); return 1; } - /* Initialize OpenAL with the default device, and check for HRTF support. */ - if(InitAL() != 0) + /* Initialize OpenAL, and check for HRTF support. */ + argv++; argc--; + if(InitAL(&argv, &argc) != 0) return 1; - if(strcmp(argv[1], "-hrtf") == 0) - { - hrtfname = argv[2]; - soundname = argv[3]; - } - else - { - hrtfname = NULL; - soundname = argv[1]; - } - device = alcGetContextsDevice(alcGetCurrentContext()); if(!alcIsExtensionPresent(device, "ALC_SOFT_HRTF")) { @@ -164,6 +154,18 @@ int main(int argc, char **argv) has_angle_ext = alIsExtensionPresent("AL_EXT_STEREO_ANGLES"); printf("AL_EXT_STEREO_ANGLES%s found\n", has_angle_ext?"":" not"); + /* Check for user-preferred HRTF */ + if(strcmp(argv[0], "-hrtf") == 0) + { + hrtfname = argv[1]; + soundname = argv[2]; + } + else + { + hrtfname = NULL; + soundname = argv[0]; + } + /* Enumerate available HRTFs, and reset the device using one. */ alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); if(!num_hrtf) diff --git a/examples/allatency.c b/examples/allatency.c index afef43ca..56d96b9e 100644 --- a/examples/allatency.c +++ b/examples/allatency.c @@ -125,15 +125,16 @@ int main(int argc, char **argv) ALdouble offsets[2]; ALenum state; - /* Print out usage if no file was specified */ + /* Print out usage if no arguments were specified */ if(argc < 2) { - fprintf(stderr, "Usage: %s <filename>\n", argv[0]); + fprintf(stderr, "Usage: %s [-device <name>] <filename>\n", argv[0]); return 1; } - /* Initialize OpenAL with the default device, and check for EFX support. */ - if(InitAL() != 0) + /* Initialize OpenAL, and check for source_latency support. */ + argv++; argc--; + if(InitAL(&argv, &argc) != 0) return 1; if(!alIsExtensionPresent("AL_SOFT_source_latency")) @@ -166,7 +167,7 @@ int main(int argc, char **argv) #undef LOAD_PROC /* Load the sound into a buffer. */ - buffer = LoadSound(argv[1]); + buffer = LoadSound(argv[0]); if(!buffer) { CloseAL(); diff --git a/examples/alreverb.c b/examples/alreverb.c index 7d2bb343..ec71f354 100644 --- a/examples/alreverb.c +++ b/examples/alreverb.c @@ -217,15 +217,16 @@ int main(int argc, char **argv) ALuint source, buffer, effect, slot; ALenum state; - /* Print out usage if no file was specified */ + /* Print out usage if no arguments were specified */ if(argc < 2) { - fprintf(stderr, "Usage: %s <filename>\n", argv[0]); + fprintf(stderr, "Usage: %s [-device <name] <filename>\n", argv[0]); return 1; } - /* Initialize OpenAL with the default device, and check for EFX support. */ - if(InitAL() != 0) + /* Initialize OpenAL, and check for EFX support. */ + argv++; argc--; + if(InitAL(&argv, &argc) != 0) return 1; if(!alcIsExtensionPresent(alcGetContextsDevice(alcGetCurrentContext()), "ALC_EXT_EFX")) @@ -269,7 +270,7 @@ int main(int argc, char **argv) #undef LOAD_PROC /* Load the sound into a buffer. */ - buffer = LoadSound(argv[1]); + buffer = LoadSound(argv[0]); if(!buffer) { CloseAL(); diff --git a/examples/alstream.c b/examples/alstream.c index 63478d6a..65a04475 100644 --- a/examples/alstream.c +++ b/examples/alstream.c @@ -270,14 +270,15 @@ int main(int argc, char **argv) StreamPlayer *player; int i; - /* Print out usage if no file was specified */ + /* Print out usage if no arguments were specified */ if(argc < 2) { - fprintf(stderr, "Usage: %s <filenames...>\n", argv[0]); + fprintf(stderr, "Usage: %s [-device <name>] <filenames...>\n", argv[0]); return 1; } - if(InitAL() != 0) + argv++; argc--; + if(InitAL(&argv, &argc) != 0) return 1; if(alIsExtensionPresent("AL_SOFT_buffer_samples")) @@ -292,7 +293,7 @@ int main(int argc, char **argv) player = NewPlayer(); /* Play each file listed on the command line */ - for(i = 1;i < argc;i++) + for(i = 0;i < argc;i++) { const char *namepart; diff --git a/examples/altonegen.c b/examples/altonegen.c index 74a04ee2..422e6d66 100644 --- a/examples/altonegen.c +++ b/examples/altonegen.c @@ -133,6 +133,7 @@ static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate) int main(int argc, char *argv[]) { enum WaveType wavetype = WT_Sine; + const char *appname = argv[0]; ALuint source, buffer; ALint last_pos, num_loops; ALint max_loops = 4; @@ -142,13 +143,24 @@ int main(int argc, char *argv[]) ALenum state; int i; - for(i = 1;i < argc;i++) + argv++; argc--; + if(InitAL(&argv, &argc) != 0) + return 1; + + if(!alIsExtensionPresent("AL_EXT_FLOAT32")) + { + fprintf(stderr, "Required AL_EXT_FLOAT32 extension not supported on this device!\n"); + CloseAL(); + return 1; + } + + for(i = 0;i < argc;i++) { if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { fprintf(stderr, "OpenAL Tone Generator\n" "\n" -"Usage: %s <options>\n" +"Usage: %s [-device <name>] <options>\n" "\n" "Available options:\n" " --help/-h This help text\n" @@ -157,8 +169,9 @@ int main(int argc, char *argv[]) " triangle, impulse\n" " --freq/-f <hz> Tone frequency (default 1000 hz)\n" " --srate/-s <sample rate> Sampling rate (default output rate)\n", - argv[0] + appname ); + CloseAL(); return 1; } else if(i+1 < argc && strcmp(argv[i], "-t") == 0) @@ -204,15 +217,6 @@ int main(int argc, char *argv[]) } } - InitAL(); - - if(!alIsExtensionPresent("AL_EXT_FLOAT32")) - { - fprintf(stderr, "Required AL_EXT_FLOAT32 extension not supported on this device!\n"); - CloseAL(); - return 1; - } - { ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); alcGetIntegerv(device, ALC_FREQUENCY, 1, &dev_rate); diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index 4582321c..43548b5c 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -29,6 +29,7 @@ * channel configs and sample types. */ #include <stdio.h> +#include <string.h> #include "AL/al.h" #include "AL/alc.h" @@ -37,15 +38,26 @@ #include "alhelpers.h" -/* InitAL opens the default device and sets up a context using default - * attributes, making the program ready to call OpenAL functions. */ -int InitAL(void) +/* InitAL opens a device and sets up a context using default attributes, making + * the program ready to call OpenAL functions. */ +int InitAL(char ***argv, int *argc) { + const ALCchar *name; ALCdevice *device; ALCcontext *ctx; - /* Open and initialize a device with default settings */ - device = alcOpenDevice(NULL); + /* Open and initialize a device */ + device = NULL; + if(argc && argv && *argc > 1 && strcmp((*argv)[0], "-device") == 0) + { + device = alcOpenDevice((*argv)[1]); + if(!device) + fprintf(stderr, "Failed to open \"%s\", trying default\n", (*argv)[1]); + (*argv) += 2; + (*argc) -= 2; + } + if(!device) + device = alcOpenDevice(NULL); if(!device) { fprintf(stderr, "Could not open a device!\n"); @@ -62,7 +74,13 @@ int InitAL(void) return 1; } - printf("Opened \"%s\"\n", alcGetString(device, ALC_DEVICE_SPECIFIER)); + name = NULL; + if(alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT")) + name = alcGetString(device, ALC_ALL_DEVICES_SPECIFIER); + if(!name || alcGetError(device) != AL_NO_ERROR) + name = alcGetString(device, ALC_DEVICE_SPECIFIER); + printf("Opened \"%s\"\n", name); + return 0; } diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h index 1b4d2fbf..9f60df2a 100644 --- a/examples/common/alhelpers.h +++ b/examples/common/alhelpers.h @@ -35,7 +35,7 @@ void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate, const ALvoid *data); /* Easy device init/deinit functions. InitAL returns 0 on success. */ -int InitAL(void); +int InitAL(char ***argv, int *argc); void CloseAL(void); #ifdef __cplusplus diff --git a/utils/openal-info.c b/utils/openal-info.c index 5b45ceef..5fd8784b 100644 --- a/utils/openal-info.c +++ b/utils/openal-info.c @@ -24,6 +24,7 @@ #include <stdio.h> #include <string.h> +#include <stdlib.h> #include "AL/alc.h" #include "AL/al.h" @@ -41,6 +42,70 @@ #endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +static WCHAR *FromUTF8(const char *str) +{ + WCHAR *out = NULL; + int len; + + if((len=MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) > 0) + { + out = calloc(sizeof(WCHAR), len); + MultiByteToWideChar(CP_UTF8, 0, str, -1, out, len); + } + return out; +} + +/* Override printf, fprintf, and fwrite so we can print UTF-8 strings. */ +static void al_fprintf(FILE *file, const char *fmt, ...) +{ + char str[1024]; + WCHAR *wstr; + va_list ap; + + va_start(ap, fmt); + vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); + + str[sizeof(str)-1] = 0; + wstr = FromUTF8(str); + if(!wstr) + fprintf(file, "<UTF-8 error> %s", str); + else + fprintf(file, "%ls", wstr); + free(wstr); +} +#define fprintf al_fprintf +#define printf(...) al_fprintf(stdout, __VA_ARGS__) + +static int al_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *file) +{ + char str[1024]; + WCHAR *wstr; + size_t len; + + len = size * nmemb; + if(len > sizeof(str)-1) + len = sizeof(str)-1; + memcpy(str, ptr, len); + str[len] = 0; + + wstr = FromUTF8(str); + if(!wstr) + fprintf(file, "<UTF-8 error> %s", str); + else + fprintf(file, "%ls", wstr); + free(wstr); + + return len / size; +} +#define fwrite al_fwrite +#endif + + #define MAX_WIDTH 80 static void printList(const char *list, char separator) |