aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Alc/backends/mmdevapi.c75
-rw-r--r--Alc/bformatdec.c4
-rw-r--r--Alc/effects/equalizer.c4
-rw-r--r--Alc/effects/modulator.c1
-rw-r--r--Alc/effects/reverb.c480
-rw-r--r--Alc/helpers.c37
-rw-r--r--Alc/hrtf.c88
-rw-r--r--Alc/mixer.c18
-rw-r--r--CMakeLists.txt28
-rw-r--r--OpenAL32/Include/alFilter.h5
-rw-r--r--OpenAL32/Include/alMain.h10
-rw-r--r--OpenAL32/Include/alu.h4
-rw-r--r--OpenAL32/alFilter.c2
-rw-r--r--appveyor.yml14
-rw-r--r--common/threads.c32
-rw-r--r--examples/alffplay.c15
-rw-r--r--examples/alhrtf.c34
-rw-r--r--examples/allatency.c11
-rw-r--r--examples/alreverb.c11
-rw-r--r--examples/alstream.c9
-rw-r--r--examples/altonegen.c28
-rw-r--r--examples/common/alhelpers.c30
-rw-r--r--examples/common/alhelpers.h2
-rw-r--r--utils/openal-info.c65
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;
}
diff --git a/Alc/hrtf.c b/Alc/hrtf.c
index 16db0c33..34070792 100644
--- a/Alc/hrtf.c
+++ b/Alc/hrtf.c
@@ -178,25 +178,37 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][
static const struct {
ALfloat elevation;
ALfloat azimuth;
- } CubePoints[8] = {
+ } Ambi3DPoints[14] = {
+ { DEG2RAD( 90.0f), DEG2RAD( 0.0f) },
{ DEG2RAD( 35.0f), DEG2RAD( -45.0f) },
{ DEG2RAD( 35.0f), DEG2RAD( 45.0f) },
- { DEG2RAD( 35.0f), DEG2RAD(-135.0f) },
{ DEG2RAD( 35.0f), DEG2RAD( 135.0f) },
+ { DEG2RAD( 35.0f), DEG2RAD(-135.0f) },
+ { DEG2RAD( 0.0f), DEG2RAD( 0.0f) },
+ { DEG2RAD( 0.0f), DEG2RAD( 90.0f) },
+ { DEG2RAD( 0.0f), DEG2RAD( 180.0f) },
+ { DEG2RAD( 0.0f), DEG2RAD( -90.0f) },
{ DEG2RAD(-35.0f), DEG2RAD( -45.0f) },
{ DEG2RAD(-35.0f), DEG2RAD( 45.0f) },
- { DEG2RAD(-35.0f), DEG2RAD(-135.0f) },
{ DEG2RAD(-35.0f), DEG2RAD( 135.0f) },
+ { DEG2RAD(-35.0f), DEG2RAD(-135.0f) },
+ { DEG2RAD(-90.0f), DEG2RAD( 0.0f) },
};
- static const ALfloat CubeMatrix[8][2][MAX_AMBI_COEFFS] = {
- { { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } },
- { { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } },
- { { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } },
- { { 0.25f, -0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, 0.125f, -0.125f } },
- { { 0.25f, 0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, -0.125f, 0.125f } },
- { { 0.25f, -0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, -0.125f, 0.125f } },
- { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } },
- { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } },
+ static const ALfloat Ambi3DMatrix[14][2][MAX_AMBI_COEFFS] = {
+ { { 0.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)