aboutsummaryrefslogtreecommitdiffstats
path: root/Alc
diff options
context:
space:
mode:
Diffstat (limited to 'Alc')
-rw-r--r--Alc/ALc.c365
-rw-r--r--Alc/ALu.c605
-rw-r--r--Alc/alcConfig.c219
-rw-r--r--Alc/alcRing.c19
-rw-r--r--Alc/alstring.h48
-rw-r--r--Alc/atomic.h180
-rw-r--r--Alc/backends/alsa.c255
-rw-r--r--Alc/backends/base.c78
-rw-r--r--Alc/backends/base.h18
-rw-r--r--Alc/backends/coreaudio.c5
-rw-r--r--Alc/backends/dsound.c753
-rw-r--r--Alc/backends/loopback.c26
-rw-r--r--Alc/backends/mmdevapi.c1109
-rw-r--r--Alc/backends/null.c90
-rw-r--r--Alc/backends/opensl.c95
-rw-r--r--Alc/backends/oss.c64
-rw-r--r--Alc/backends/portaudio.c4
-rw-r--r--Alc/backends/pulseaudio.c339
-rw-r--r--Alc/backends/qsa.c60
-rw-r--r--Alc/backends/sndio.c18
-rw-r--r--Alc/backends/solaris.c20
-rw-r--r--Alc/backends/wave.c83
-rw-r--r--Alc/backends/winmm.c333
-rw-r--r--Alc/compat.h43
-rw-r--r--Alc/effects/autowah.c21
-rw-r--r--Alc/effects/chorus.c42
-rw-r--r--Alc/effects/compressor.c7
-rw-r--r--Alc/effects/dedicated.c7
-rw-r--r--Alc/effects/distortion.c7
-rw-r--r--Alc/effects/echo.c9
-rw-r--r--Alc/effects/equalizer.c7
-rw-r--r--Alc/effects/flanger.c42
-rw-r--r--Alc/effects/modulator.c7
-rw-r--r--Alc/effects/null.c18
-rw-r--r--Alc/effects/reverb.c9
-rw-r--r--Alc/helpers.c593
-rw-r--r--Alc/hrtf.c62
-rw-r--r--Alc/hrtf.h28
-rw-r--r--Alc/hrtf_tables.inc848
-rw-r--r--Alc/midi/base.h9
-rw-r--r--Alc/midi/dummy.c12
-rw-r--r--Alc/midi/fluidsynth.c17
-rw-r--r--Alc/midi/sf2load.c269
-rw-r--r--Alc/midi/soft.c141
-rw-r--r--Alc/mixer.c169
-rw-r--r--Alc/mixer_c.c118
-rw-r--r--Alc/mixer_defs.h75
-rw-r--r--Alc/mixer_inc.c119
-rw-r--r--Alc/mixer_neon.c130
-rw-r--r--Alc/mixer_sse.c205
-rw-r--r--Alc/mixer_sse2.c78
-rw-r--r--Alc/mixer_sse41.c82
-rw-r--r--Alc/rwlock.h21
-rw-r--r--Alc/threads.c200
-rw-r--r--Alc/uintmap.h34
-rw-r--r--Alc/vector.h69
56 files changed, 3940 insertions, 4344 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c
index 805be2fa..7c8c2322 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -39,6 +39,10 @@
#include "bs2b.h"
#include "alu.h"
+#include "compat.h"
+#include "threads.h"
+#include "alstring.h"
+
#include "backends/base.h"
#include "midi/base.h"
@@ -79,10 +83,10 @@ static struct BackendInfo BackendList[] = {
{ "qsa", NULL, alc_qsa_init, alc_qsa_deinit, alc_qsa_probe, EmptyFuncs },
#endif
#ifdef HAVE_MMDEVAPI
- { "mmdevapi", NULL, alcMMDevApiInit, alcMMDevApiDeinit, alcMMDevApiProbe, EmptyFuncs },
+ { "mmdevapi", ALCmmdevBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
#ifdef HAVE_DSOUND
- { "dsound", NULL, alcDSoundInit, alcDSoundDeinit, alcDSoundProbe, EmptyFuncs },
+ { "dsound", ALCdsoundBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
#ifdef HAVE_WINMM
{ "winmm", NULL, alcWinMMInit, alcWinMMDeinit, alcWinMMProbe, EmptyFuncs },
@@ -445,6 +449,8 @@ static const ALCenums enumeration[] = {
DECL(AL_FORMAT_STEREO_DOUBLE_EXT),
DECL(AL_FORMAT_MONO_IMA4),
DECL(AL_FORMAT_STEREO_IMA4),
+ DECL(AL_FORMAT_MONO_MSADPCM_SOFT),
+ DECL(AL_FORMAT_STEREO_MSADPCM_SOFT),
DECL(AL_FORMAT_QUAD8_LOKI),
DECL(AL_FORMAT_QUAD16_LOKI),
DECL(AL_FORMAT_QUAD8),
@@ -523,6 +529,8 @@ static const ALCenums enumeration[] = {
DECL(AL_BYTE_LENGTH_SOFT),
DECL(AL_SAMPLE_LENGTH_SOFT),
DECL(AL_SEC_LENGTH_SOFT),
+ DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT),
+ DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT),
DECL(AL_UNUSED),
DECL(AL_PENDING),
@@ -557,14 +565,19 @@ static const ALCenums enumeration[] = {
DECL(AL_FILTER_TYPE),
DECL(AL_FILTER_NULL),
DECL(AL_FILTER_LOWPASS),
-#if 0
DECL(AL_FILTER_HIGHPASS),
DECL(AL_FILTER_BANDPASS),
-#endif
DECL(AL_LOWPASS_GAIN),
DECL(AL_LOWPASS_GAINHF),
+ DECL(AL_HIGHPASS_GAIN),
+ DECL(AL_HIGHPASS_GAINLF),
+
+ DECL(AL_BANDPASS_GAIN),
+ DECL(AL_BANDPASS_GAINHF),
+ DECL(AL_BANDPASS_GAINLF),
+
DECL(AL_EFFECT_TYPE),
DECL(AL_EFFECT_NULL),
DECL(AL_EFFECT_REVERB),
@@ -691,11 +704,9 @@ static const ALCchar alcErrOutOfMemory[] = "Out of Memory";
/* Enumerated device names */
static const ALCchar alcDefaultName[] = "OpenAL Soft\0";
-static ALCchar *alcAllDevicesList;
-static ALCchar *alcCaptureDeviceList;
-/* Sizes only include the first ending null character, not the second */
-static size_t alcAllDevicesListSize;
-static size_t alcCaptureDeviceListSize;
+
+static al_string alcAllDevicesList;
+static al_string alcCaptureDeviceList;
/* Default is always the first in the list */
static ALCchar *alcDefaultAllDevicesSpecifier;
@@ -706,14 +717,15 @@ static const ALchar alExtList[] =
"AL_EXT_ALAW AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 "
"AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW "
"AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model "
- "AL_LOKI_quadriphonic AL_SOFT_buffer_samples AL_SOFT_buffer_sub_data "
- "AL_SOFT_deferred_updates AL_SOFT_direct_channels AL_SOFT_loop_points "
- "AL_SOFT_source_latency";
+ "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_buffer_samples "
+ "AL_SOFT_buffer_sub_data AL_SOFT_deferred_updates AL_SOFT_direct_channels "
+ "AL_SOFT_loop_points AL_SOFTX_MSADPCM AL_SOFT_source_latency "
+ "AL_SOFTX_source_length";
static volatile ALCenum LastNullDeviceError = ALC_NO_ERROR;
/* Thread-local current context */
-static althread_key_t LocalContext;
+static altss_t LocalContext;
/* Process-wide current context */
static ALCcontext *volatile GlobalContext = NULL;
@@ -731,7 +743,7 @@ enum LogLevel LogLevel = LogError;
static ALCboolean TrapALCError = ALC_FALSE;
/* One-time configuration init control */
-static althread_once_t alc_config_once = ALTHREAD_ONCE_INIT;
+static alonce_flag alc_config_once = AL_ONCE_FLAG_INIT;
/* Default effect that applies to sources that don't have an effect on send 0 */
static ALeffect DefaultEffect;
@@ -760,15 +772,16 @@ static const ALCint alcEFXMinorVersion = 0;
************************************************/
static ALCdevice *volatile DeviceList = NULL;
-static CRITICAL_SECTION ListLock;
-
-static void LockLists(void)
+static almtx_t ListLock;
+static inline void LockLists(void)
{
- EnterCriticalSection(&ListLock);
+ int lockret = almtx_lock(&ListLock);
+ assert(lockret == althrd_success);
}
-static void UnlockLists(void)
+static inline void UnlockLists(void)
{
- LeaveCriticalSection(&ListLock);
+ int unlockret = almtx_unlock(&ListLock);
+ assert(unlockret == althrd_success);
}
/************************************************
@@ -779,34 +792,19 @@ static void alc_init(void);
static void alc_deinit(void);
static void alc_deinit_safe(void);
-UIntMap TlsDestructor;
-
#ifndef AL_LIBTYPE_STATIC
-BOOL APIENTRY DllMain(HINSTANCE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
+BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reason, LPVOID lpReserved)
{
- ALsizei i;
-
- // Perform actions based on the reason for calling.
- switch(ul_reason_for_call)
+ switch(reason)
{
case DLL_PROCESS_ATTACH:
/* Pin the DLL so we won't get unloaded until the process terminates */
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(WCHAR*)hModule, &hModule);
- InitUIntMap(&TlsDestructor, ~0);
alc_init();
break;
case DLL_THREAD_DETACH:
- LockUIntMapRead(&TlsDestructor);
- for(i = 0;i < TlsDestructor.size;i++)
- {
- void *ptr = althread_getspecific(TlsDestructor.array[i].key);
- void (*callback)(void*) = (void(*)(void*))TlsDestructor.array[i].value;
- if(ptr && callback)
- callback(ptr);
- }
- UnlockUIntMapRead(&TlsDestructor);
break;
case DLL_PROCESS_DETACH:
@@ -814,7 +812,6 @@ BOOL APIENTRY DllMain(HINSTANCE hModule,DWORD ul_reason_for_call,LPVOID lpReserv
alc_deinit();
else
alc_deinit_safe();
- ResetUIntMap(&TlsDestructor);
break;
}
return TRUE;
@@ -855,9 +852,13 @@ static void ReleaseThreadCtx(void *ptr);
static void alc_init(void)
{
const char *str;
+ int ret;
LogFile = stderr;
+ AL_STRING_INIT(alcAllDevicesList);
+ AL_STRING_INIT(alcCaptureDeviceList);
+
str = getenv("__ALSOFT_HALF_ANGLE_CONES");
if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1))
ConeScale *= 0.5f;
@@ -866,8 +867,12 @@ static void alc_init(void)
if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1))
ZScale *= -1.0f;
- althread_key_create(&LocalContext, ReleaseThreadCtx);
- InitializeCriticalSection(&ListLock);
+ ret = altss_create(&LocalContext, ReleaseThreadCtx);
+ assert(ret == althrd_success);
+
+ ret = almtx_init(&ListLock, almtx_recursive);
+ assert(ret == althrd_success);
+
ThunkInit();
}
@@ -889,7 +894,7 @@ static void alc_initconfig(void)
str = getenv("ALSOFT_LOGFILE");
if(str && str[0])
{
- FILE *logfile = fopen(str, "wt");
+ FILE *logfile = al_fopen(str, "wt");
if(logfile) LogFile = logfile;
else ERR("Failed to open log file '%s'\n", str);
}
@@ -904,8 +909,12 @@ static void alc_initconfig(void)
ReadALConfig();
capfilter = 0;
-#ifdef HAVE_SSE
+#if defined(HAVE_SSE4_1)
+ capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE4_1;
+#elif defined(HAVE_SSE2)
capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2;
+#elif defined(HAVE_SSE)
+ capfilter |= CPU_CAP_SSE;
#endif
#ifdef HAVE_NEON
capfilter |= CPU_CAP_NEON;
@@ -935,6 +944,8 @@ static void alc_initconfig(void)
capfilter &= ~CPU_CAP_SSE;
else if(len == 4 && strncasecmp(str, "sse2", len) == 0)
capfilter &= ~CPU_CAP_SSE2;
+ else if(len == 6 && strncasecmp(str, "sse4.1", len) == 0)
+ capfilter &= ~CPU_CAP_SSE4_1;
else if(len == 4 && strncasecmp(str, "neon", len) == 0)
capfilter &= ~CPU_CAP_NEON;
else
@@ -1140,7 +1151,7 @@ static void alc_initconfig(void)
if((str && str[0]) || ConfigValueStr(NULL, "default-reverb", &str))
LoadReverbPreset(str, &DefaultEffect);
}
-#define DO_INITCONFIG() althread_once(&alc_config_once, alc_initconfig)
+#define DO_INITCONFIG() alcall_once(&alc_config_once, alc_initconfig)
/************************************************
@@ -1150,10 +1161,8 @@ static void alc_cleanup(void)
{
ALCdevice *dev;
- free(alcAllDevicesList); alcAllDevicesList = NULL;
- alcAllDevicesListSize = 0;
- free(alcCaptureDeviceList); alcCaptureDeviceList = NULL;
- alcCaptureDeviceListSize = 0;
+ AL_STRING_DEINIT(alcAllDevicesList);
+ AL_STRING_DEINIT(alcCaptureDeviceList);
free(alcDefaultAllDevicesSpecifier);
alcDefaultAllDevicesSpecifier = NULL;
@@ -1180,8 +1189,8 @@ static void alc_deinit_safe(void)
FreeALConfig();
ThunkExit();
- DeleteCriticalSection(&ListLock);
- althread_key_delete(LocalContext);
+ almtx_destroy(&ListLock);
+ altss_delete(LocalContext);
if(LogFile != stderr)
fclose(LogFile);
@@ -1219,14 +1228,12 @@ static void alc_deinit(void)
/************************************************
* Device enumeration
************************************************/
-static void ProbeList(ALCchar **list, size_t *listsize, enum DevProbe type)
+static void ProbeDevices(al_string *list, enum DevProbe type)
{
DO_INITCONFIG();
LockLists();
- free(*list);
- *list = NULL;
- *listsize = 0;
+ al_string_clear(list);
if(type == ALL_DEVICE_PROBE && (PlaybackBackend.Probe || PlaybackBackend.getFactory))
{
@@ -1250,42 +1257,24 @@ static void ProbeList(ALCchar **list, size_t *listsize, enum DevProbe type)
}
UnlockLists();
}
-
static void ProbeAllDevicesList(void)
-{ ProbeList(&alcAllDevicesList, &alcAllDevicesListSize, ALL_DEVICE_PROBE); }
+{ ProbeDevices(&alcAllDevicesList, ALL_DEVICE_PROBE); }
static void ProbeCaptureDeviceList(void)
-{ ProbeList(&alcCaptureDeviceList, &alcCaptureDeviceListSize, CAPTURE_DEVICE_PROBE); }
-
+{ ProbeDevices(&alcCaptureDeviceList, CAPTURE_DEVICE_PROBE); }
-static void AppendList(const ALCchar *name, ALCchar **List, size_t *ListSize)
+static void AppendDevice(const ALCchar *name, al_string *devnames)
{
size_t len = strlen(name);
- void *temp;
-
- if(len == 0)
- return;
-
- temp = realloc(*List, (*ListSize) + len + 2);
- if(!temp)
+ if(len > 0)
{
- ERR("Realloc failed to add %s!\n", name);
- return;
+ al_string_append_range(devnames, name, name+len);
+ al_string_append_char(devnames, '\0');
}
- *List = temp;
-
- memcpy((*List)+(*ListSize), name, len+1);
- *ListSize += len+1;
- (*List)[*ListSize] = 0;
}
-
-#define DECL_APPEND_LIST_FUNC(type) \
-void Append##type##List(const ALCchar *name) \
-{ AppendList(name, &alc##type##List, &alc##type##ListSize); }
-
-DECL_APPEND_LIST_FUNC(AllDevices)
-DECL_APPEND_LIST_FUNC(CaptureDevice)
-
-#undef DECL_APPEND_LIST_FUNC
+void AppendAllDevicesList(const ALCchar *name)
+{ AppendDevice(name, &alcAllDevicesList); }
+void AppendCaptureDeviceList(const ALCchar *name)
+{ AppendDevice(name, &alcCaptureDeviceList); }
/************************************************
@@ -1350,8 +1339,8 @@ ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
return 0;
}
-static ALboolean DecomposeDevFormat(ALenum format, enum DevFmtChannels *chans,
- enum DevFmtType *type)
+DECL_CONST static ALboolean DecomposeDevFormat(ALenum format,
+ enum DevFmtChannels *chans, enum DevFmtType *type)
{
static const struct {
ALenum format;
@@ -1397,7 +1386,7 @@ static ALboolean DecomposeDevFormat(ALenum format, enum DevFmtChannels *chans,
return AL_FALSE;
}
-static ALCboolean IsValidALCType(ALCenum type)
+DECL_CONST static ALCboolean IsValidALCType(ALCenum type)
{
switch(type)
{
@@ -1413,7 +1402,7 @@ static ALCboolean IsValidALCType(ALCenum type)
return ALC_FALSE;
}
-static ALCboolean IsValidALCChannels(ALCenum channels)
+DECL_CONST static ALCboolean IsValidALCChannels(ALCenum channels)
{
switch(channels)
{
@@ -1603,7 +1592,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
enum DevFmtType oldType;
ALCuint oldFreq;
FPUCtl oldMode;
- ALuint i;
// Check for attributes
if(device->Type == Loopback)
@@ -1791,16 +1779,25 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
device->Frequency,
device->UpdateSize, device->NumUpdates);
+ if(device->Type != Loopback)
+ {
+ int nohrtf = !(device->Flags&DEVICE_HRTF_REQUEST);
+ if(GetConfigValueBool(NULL, "hrtf", !nohrtf))
+ device->Flags |= DEVICE_HRTF_REQUEST;
+ else
+ device->Flags &= ~DEVICE_HRTF_REQUEST;
+ }
if((device->Flags&DEVICE_HRTF_REQUEST))
{
enum DevFmtChannels chans;
ALCuint freq;
-
- FindHrtfFormat(device, &chans, &freq);
- device->Frequency = freq;
- device->FmtChans = chans;
- device->Flags |= DEVICE_CHANNELS_REQUEST |
- DEVICE_FREQUENCY_REQUEST;
+ if(FindHrtfFormat(device, &chans, &freq))
+ {
+ device->Frequency = freq;
+ device->FmtChans = chans;
+ device->Flags |= DEVICE_CHANNELS_REQUEST |
+ DEVICE_FREQUENCY_REQUEST;
+ }
}
if(V0(device->Backend,reset)() == ALC_FALSE)
@@ -1831,22 +1828,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
aluInitPanning(device);
- for(i = 0;i < MaxChannels;i++)
- {
- device->ClickRemoval[i] = 0.0f;
- device->PendingClicks[i] = 0.0f;
- }
-
V(device->Synth,update)(device);
device->Hrtf = NULL;
- if(device->Type != Loopback && ConfigValueExists(NULL, "hrtf"))
- {
- if(GetConfigValueBool(NULL, "hrtf", AL_FALSE))
- device->Flags |= DEVICE_HRTF_REQUEST;
- else
- device->Flags &= ~DEVICE_HRTF_REQUEST;
- }
if((device->Flags&DEVICE_HRTF_REQUEST))
{
device->Hrtf = GetHrtf(device);
@@ -1924,11 +1908,26 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
source->Send[s].GainHF = 1.0f;
s++;
}
- source->NeedsUpdate = AL_FALSE;
- ALsource_Update(source, context);
+ source->NeedsUpdate = AL_TRUE;
}
UnlockUIntMapRead(&context->SourceMap);
+ for(pos = 0;pos < context->ActiveSourceCount;pos++)
+ {
+ ALactivesource *src = context->ActiveSources[pos];
+ ALsource *source = src->Source;
+ ALuint s = device->NumAuxSends;
+ while(s < MAX_SENDS)
+ {
+ src->Send[s].Moving = AL_FALSE;
+ src->Send[s].Counter = 0;
+ s++;
+ }
+
+ src->Update(src, context);
+ source->NeedsUpdate = AL_FALSE;
+ }
+
context = context->next;
}
if(device->DefaultSlot)
@@ -2029,8 +2028,7 @@ static ALCvoid FreeDevice(ALCdevice *device)
free(device->Bs2b);
device->Bs2b = NULL;
- free(device->DeviceName);
- device->DeviceName = NULL;
+ AL_STRING_DEINIT(device->DeviceName);
al_free(device);
}
@@ -2038,14 +2036,14 @@ static ALCvoid FreeDevice(ALCdevice *device)
void ALCdevice_IncRef(ALCdevice *device)
{
- RefCount ref;
+ uint ref;
ref = IncrementRef(&device->ref);
TRACEREF("%p increasing refcount to %u\n", device, ref);
}
void ALCdevice_DecRef(ALCdevice *device)
{
- RefCount ref;
+ uint ref;
ref = DecrementRef(&device->ref);
TRACEREF("%p decreasing refcount to %u\n", device, ref);
if(ref == 0) FreeDevice(device);
@@ -2131,6 +2129,8 @@ static ALvoid InitContext(ALCcontext *Context)
*/
static ALCvoid FreeContext(ALCcontext *context)
{
+ ALsizei i;
+
TRACE("%p\n", context);
if(context->SourceMap.size > 0)
@@ -2147,15 +2147,17 @@ static ALCvoid FreeContext(ALCcontext *context)
}
ResetUIntMap(&context->EffectSlotMap);
- context->ActiveSourceCount = 0;
+ for(i = 0;i < context->MaxActiveSources;i++)
+ {
+ al_free(context->ActiveSources[i]);
+ context->ActiveSources[i] = NULL;
+ }
free(context->ActiveSources);
context->ActiveSources = NULL;
+ context->ActiveSourceCount = 0;
context->MaxActiveSources = 0;
- context->ActiveEffectSlotCount = 0;
- free(context->ActiveEffectSlots);
- context->ActiveEffectSlots = NULL;
- context->MaxActiveEffectSlots = 0;
+ VECTOR_DEINIT(context->ActiveAuxSlots);
ALCdevice_DecRef(context->Device);
context->Device = NULL;
@@ -2174,21 +2176,21 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device)
{
ALCcontext *volatile*tmp_ctx;
- if(althread_getspecific(LocalContext) == context)
+ if(altss_get(LocalContext) == context)
{
WARN("%p released while current on thread\n", context);
- althread_setspecific(LocalContext, NULL);
+ altss_set(LocalContext, NULL);
ALCcontext_DecRef(context);
}
- if(CompExchangePtr((XchgPtr*)&GlobalContext, context, NULL))
+ if(CompExchangePtr((XchgPtr*)&GlobalContext, context, NULL) == context)
ALCcontext_DecRef(context);
ALCdevice_Lock(device);
tmp_ctx = &device->ContextList;
while(*tmp_ctx)
{
- if(CompExchangePtr((XchgPtr*)tmp_ctx, context, context->next))
+ if(CompExchangePtr((XchgPtr*)tmp_ctx, context, context->next) == context)
break;
tmp_ctx = &(*tmp_ctx)->next;
}
@@ -2199,14 +2201,14 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device)
void ALCcontext_IncRef(ALCcontext *context)
{
- RefCount ref;
+ uint ref;
ref = IncrementRef(&context->ref);
TRACEREF("%p increasing refcount to %u\n", context, ref);
}
void ALCcontext_DecRef(ALCcontext *context)
{
- RefCount ref;
+ uint ref;
ref = DecrementRef(&context->ref);
TRACEREF("%p decreasing refcount to %u\n", context, ref);
if(ref == 0) FreeContext(context);
@@ -2258,7 +2260,7 @@ ALCcontext *GetContextRef(void)
{
ALCcontext *context;
- context = althread_getspecific(LocalContext);
+ context = altss_get(LocalContext);
if(context)
ALCcontext_IncRef(context);
else
@@ -2356,26 +2358,26 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
case ALC_ALL_DEVICES_SPECIFIER:
if(VerifyDevice(Device))
{
- value = Device->DeviceName;
+ value = al_string_get_cstr(Device->DeviceName);
ALCdevice_DecRef(Device);
}
else
{
ProbeAllDevicesList();
- value = alcAllDevicesList;
+ value = al_string_get_cstr(alcAllDevicesList);
}
break;
case ALC_CAPTURE_DEVICE_SPECIFIER:
if(VerifyDevice(Device))
{
- value = Device->DeviceName;
+ value = al_string_get_cstr(Device->DeviceName);
ALCdevice_DecRef(Device);
}
else
{
ProbeCaptureDeviceList();
- value = alcCaptureDeviceList;
+ value = al_string_get_cstr(alcCaptureDeviceList);
}
break;
@@ -2385,14 +2387,13 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
break;
case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
- if(!alcAllDevicesList)
+ if(al_string_empty(alcAllDevicesList))
ProbeAllDevicesList();
Device = VerifyDevice(Device);
free(alcDefaultAllDevicesSpecifier);
- alcDefaultAllDevicesSpecifier = strdup(alcAllDevicesList ?
- alcAllDevicesList : "");
+ alcDefaultAllDevicesSpecifier = strdup(al_string_get_cstr(alcAllDevicesList));
if(!alcDefaultAllDevicesSpecifier)
alcSetError(Device, ALC_OUT_OF_MEMORY);
@@ -2401,14 +2402,13 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
break;
case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
- if(!alcCaptureDeviceList)
+ if(al_string_empty(alcCaptureDeviceList))
ProbeCaptureDeviceList();
Device = VerifyDevice(Device);
free(alcCaptureDefaultDeviceSpecifier);
- alcCaptureDefaultDeviceSpecifier = strdup(alcCaptureDeviceList ?
- alcCaptureDeviceList : "");
+ alcCaptureDefaultDeviceSpecifier = strdup(al_string_get_cstr(alcAllDevicesList));
if(!alcCaptureDefaultDeviceSpecifier)
alcSetError(Device, ALC_OUT_OF_MEMORY);
@@ -2864,15 +2864,17 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
return NULL;
}
- ALContext = calloc(1, sizeof(ALCcontext)+15+sizeof(ALlistener));
+ ALContext = calloc(1, sizeof(ALCcontext)+sizeof(ALlistener));
if(ALContext)
{
- ALContext->ref = 1;
- ALContext->Listener = (ALlistener*)(((ALintptrEXT)(ALContext+1)+15)&~15);
+ InitRef(&ALContext->ref, 1);
+ ALContext->Listener = (ALlistener*)ALContext->_listener_mem;
+
+ VECTOR_INIT(ALContext->ActiveAuxSlots);
ALContext->MaxActiveSources = 256;
- ALContext->ActiveSources = malloc(sizeof(ALContext->ActiveSources[0]) *
- ALContext->MaxActiveSources);
+ ALContext->ActiveSources = calloc(ALContext->MaxActiveSources,
+ sizeof(ALContext->ActiveSources[0]));
}
if(!ALContext || !ALContext->ActiveSources)
{
@@ -2883,8 +2885,16 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
}
UnlockLists();
- free(ALContext);
- ALContext = NULL;
+ if(ALContext)
+ {
+ free(ALContext->ActiveSources);
+ ALContext->ActiveSources = NULL;
+
+ VECTOR_DEINIT(ALContext->ActiveAuxSlots);
+
+ free(ALContext);
+ ALContext = NULL;
+ }
alcSetError(device, ALC_OUT_OF_MEMORY);
ALCdevice_DecRef(device);
@@ -2897,7 +2907,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
do {
ALContext->next = device->ContextList;
- } while(!CompExchangePtr((XchgPtr*)&device->ContextList, ALContext->next, ALContext));
+ } while(CompExchangePtr((XchgPtr*)&device->ContextList, ALContext->next, ALContext) != ALContext->next);
UnlockLists();
ALCdevice_DecRef(device);
@@ -2938,7 +2948,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
{
ALCcontext *Context;
- Context = althread_getspecific(LocalContext);
+ Context = altss_get(LocalContext);
if(!Context) Context = GlobalContext;
return Context;
@@ -2951,7 +2961,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
{
ALCcontext *Context;
- Context = althread_getspecific(LocalContext);
+ Context = altss_get(LocalContext);
return Context;
}
@@ -2973,9 +2983,9 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
context = ExchangePtr((XchgPtr*)&GlobalContext, context);
if(context) ALCcontext_DecRef(context);
- if((context=althread_getspecific(LocalContext)) != NULL)
+ if((context=altss_get(LocalContext)) != NULL)
{
- althread_setspecific(LocalContext, NULL);
+ altss_set(LocalContext, NULL);
ALCcontext_DecRef(context);
}
@@ -2997,8 +3007,8 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
return ALC_FALSE;
}
/* context's reference count is already incremented */
- old = althread_getspecific(LocalContext);
- althread_setspecific(LocalContext, context);
+ old = altss_get(LocalContext);
+ altss_set(LocalContext, context);
if(old) ALCcontext_DecRef(old);
return ALC_TRUE;
@@ -3046,7 +3056,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0))
deviceName = NULL;
- device = al_calloc(16, sizeof(ALCdevice)+15+sizeof(ALeffectslot));
+ device = al_calloc(16, sizeof(ALCdevice)+sizeof(ALeffectslot));
if(!device)
{
alcSetError(NULL, ALC_OUT_OF_MEMORY);
@@ -3054,7 +3064,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
}
//Validate device
- device->ref = 1;
+ InitRef(&device->ref, 1);
device->Connected = ALC_TRUE;
device->Type = Playback;
device->LastError = ALC_NO_ERROR;
@@ -3062,7 +3072,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
device->Flags = 0;
device->Bs2b = NULL;
device->Bs2bLevel = 0;
- device->DeviceName = NULL;
+ AL_STRING_INIT(device->DeviceName);
device->ContextList = NULL;
@@ -3088,10 +3098,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
device->UpdateSize = 1024;
if(!PlaybackBackend.getFactory)
- {
- device->Funcs = &PlaybackBackend.Funcs;
- device->Backend = create_backend_wrapper(device, ALCbackend_Playback);
- }
+ device->Backend = create_backend_wrapper(device, &PlaybackBackend.Funcs,
+ ALCbackend_Playback);
else
{
ALCbackendFactory *factory = PlaybackBackend.getFactory();
@@ -3261,7 +3269,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
if(DefaultEffect.type != AL_EFFECT_NULL)
{
- device->DefaultSlot = (ALeffectslot*)(((ALintptrEXT)(device+1)+15)&~15);
+ device->DefaultSlot = (ALeffectslot*)device->_slot_mem;
if(InitEffectSlot(device->DefaultSlot) != AL_NO_ERROR)
{
device->DefaultSlot = NULL;
@@ -3278,9 +3286,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
do {
device->next = DeviceList;
- } while(!CompExchangePtr((XchgPtr*)&DeviceList, device->next, device));
+ } while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next);
- TRACE("Created device %p, \"%s\"\n", device, device->DeviceName);
+ TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName));
return device;
}
@@ -3356,10 +3364,12 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
}
//Validate device
- device->ref = 1;
+ InitRef(&device->ref, 1);
device->Connected = ALC_TRUE;
device->Type = Capture;
+ AL_STRING_INIT(device->DeviceName);
+
InitUIntMap(&device->BufferMap, ~0);
InitUIntMap(&device->EffectMap, ~0);
InitUIntMap(&device->FilterMap, ~0);
@@ -3367,13 +3377,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
InitUIntMap(&device->PresetMap, ~0);
InitUIntMap(&device->FontsoundMap, ~0);
- device->DeviceName = NULL;
-
if(!CaptureBackend.getFactory)
- {
- device->Funcs = &CaptureBackend.Funcs;
- device->Backend = create_backend_wrapper(device, ALCbackend_Capture);
- }
+ device->Backend = create_backend_wrapper(device, &CaptureBackend.Funcs,
+ ALCbackend_Capture);
else
{
ALCbackendFactory *factory = CaptureBackend.getFactory();
@@ -3409,9 +3415,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
do {
device->next = DeviceList;
- } while(!CompExchangePtr((XchgPtr*)&DeviceList, device->next, device));
+ } while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next);
- TRACE("Created device %p, \"%s\"\n", device, device->DeviceName);
+ TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName));
return device;
}
@@ -3524,7 +3530,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
}
//Validate device
- device->ref = 1;
+ InitRef(&device->ref, 1);
device->Connected = ALC_TRUE;
device->Type = Loopback;
device->LastError = ALC_NO_ERROR;
@@ -3532,7 +3538,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
device->Flags = 0;
device->Bs2b = NULL;
device->Bs2bLevel = 0;
- device->DeviceName = NULL;
+ AL_STRING_INIT(device->DeviceName);
device->ContextList = NULL;
@@ -3592,7 +3598,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
V(device->Backend,open)("Loopback");
do {
device->next = DeviceList;
- } while(!CompExchangePtr((XchgPtr*)&DeviceList, device->next, device));
+ } while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next);
TRACE("Created device %p\n", device);
return device;
@@ -3676,17 +3682,18 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device)
LockLists();
if((device->Flags&DEVICE_PAUSED))
{
- if(V0(device->Backend,start)() != ALC_FALSE)
+ device->Flags &= ~DEVICE_PAUSED;
+ if(device->ContextList != NULL)
{
- device->Flags |= DEVICE_RUNNING;
- device->Flags &= ~DEVICE_PAUSED;
- }
- else
- {
- alcSetError(device, ALC_INVALID_DEVICE);
- ALCdevice_Lock(device);
- aluHandleDisconnect(device);
- ALCdevice_Unlock(device);
+ if(V0(device->Backend,start)() != ALC_FALSE)
+ device->Flags |= DEVICE_RUNNING;
+ else
+ {
+ alcSetError(device, ALC_INVALID_DEVICE);
+ ALCdevice_Lock(device);
+ aluHandleDisconnect(device);
+ ALCdevice_Unlock(device);
+ }
}
}
UnlockLists();
diff --git a/Alc/ALu.c b/Alc/ALu.c
index fd8065ed..488a7273 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -33,12 +33,17 @@
#include "alAuxEffectSlot.h"
#include "alu.h"
#include "bs2b.h"
+#include "hrtf.h"
+#include "static_assert.h"
#include "mixer_defs.h"
#include "midi/base.h"
+static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE,
+ "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
+
struct ChanMap {
enum Channel channel;
ALfloat angle;
@@ -86,6 +91,14 @@ static ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment)
case PointResampler:
return Resample_point32_C;
case LinearResampler:
+#ifdef HAVE_SSE4_1
+ if((CPUCapFlags&CPU_CAP_SSE4_1))
+ return Resample_lerp32_SSE41;
+#endif
+#ifdef HAVE_SSE2
+ if((CPUCapFlags&CPU_CAP_SSE2))
+ return Resample_lerp32_SSE2;
+#endif
return Resample_lerp32_C;
case CubicResampler:
return Resample_cubic32_C;
@@ -98,7 +111,7 @@ static ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment)
}
-static DryMixerFunc SelectHrtfMixer(void)
+static HrtfMixerFunc SelectHrtfMixer(void)
{
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
@@ -226,7 +239,7 @@ static ALvoid CalcListenerParams(ALlistener *Listener)
aluMatrixVector(Listener->Params.Velocity, 0.0f, Listener->Params.Matrix);
}
-ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
+ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
{
static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } };
static const struct ChanMap StereoMap[2] = {
@@ -276,13 +289,14 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
};
ALCdevice *Device = ALContext->Device;
+ const ALsource *ALSource = src->Source;
ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
ALbufferlistitem *BufferListItem;
enum FmtChannels Channels;
- ALfloat (*SrcMatrix)[MaxChannels];
- ALfloat DryGain, DryGainHF;
+ ALfloat DryGain, DryGainHF, DryGainLF;
ALfloat WetGain[MAX_SENDS];
ALfloat WetGainHF[MAX_SENDS];
+ ALfloat WetGainLF[MAX_SENDS];
ALint NumSends, Frequency;
const struct ChanMap *chans = NULL;
enum Resampler Resampler;
@@ -290,7 +304,7 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALboolean DirectChannels;
ALfloat hwidth = 0.0f;
ALfloat Pitch;
- ALint i, c;
+ ALint i, j, c;
/* Get device properties */
NumSends = Device->NumAuxSends;
@@ -307,6 +321,18 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
Resampler = ALSource->Resampler;
DirectChannels = ALSource->DirectChannels;
+ src->Direct.OutBuffer = Device->DryBuffer;
+ for(i = 0;i < NumSends;i++)
+ {
+ ALeffectslot *Slot = ALSource->Send[i].Slot;
+ if(!Slot && i == 0)
+ Slot = Device->DefaultSlot;
+ if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
+ src->Send[i].OutBuffer = NULL;
+ else
+ src->Send[i].OutBuffer = Slot->WetBuffer;
+ }
+
/* Calculate the stepping value */
Channels = FmtMono;
BufferListItem = ALSource->queue;
@@ -316,44 +342,35 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
if((ALBuffer=BufferListItem->buffer) != NULL)
{
Pitch = Pitch * ALBuffer->Frequency / Frequency;
- if(Pitch > 10.0f)
- ALSource->Params.Step = 10<<FRACTIONBITS;
+ if(Pitch > (ALfloat)MAX_PITCH)
+ src->Step = MAX_PITCH<<FRACTIONBITS;
else
{
- ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
- if(ALSource->Params.Step == 0)
- ALSource->Params.Step = 1;
+ src->Step = fastf2i(Pitch*FRACTIONONE);
+ if(src->Step == 0)
+ src->Step = 1;
}
- ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step);
+ src->Resample = SelectResampler(Resampler, src->Step);
Channels = ALBuffer->FmtChannels;
break;
}
BufferListItem = BufferListItem->next;
}
- if(!DirectChannels && Device->Hrtf)
- ALSource->Params.DryMix = SelectHrtfMixer();
- else
- ALSource->Params.DryMix = SelectDirectMixer();
- ALSource->Params.WetMix = SelectSendMixer();
/* Calculate gains */
DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
- DryGain *= ALSource->DirectGain * ListenerGain;
- DryGainHF = ALSource->DirectGainHF;
+ DryGain *= ALSource->Direct.Gain * ListenerGain;
+ DryGainHF = ALSource->Direct.GainHF;
+ DryGainLF = ALSource->Direct.GainLF;
for(i = 0;i < NumSends;i++)
{
- WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
- WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
+ WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
+ WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
WetGainHF[i] = ALSource->Send[i].GainHF;
+ WetGainLF[i] = ALSource->Send[i].GainLF;
}
- SrcMatrix = ALSource->Params.Direct.Gains;
- for(i = 0;i < MAX_INPUT_CHANNELS;i++)
- {
- for(c = 0;c < MaxChannels;c++)
- SrcMatrix[i][c] = 0.0f;
- }
switch(Channels)
{
case FmtMono:
@@ -410,16 +427,64 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
{
for(c = 0;c < num_channels;c++)
{
+ ALfloat *restrict Target = src->Direct.Mix.Gains[c].Target;
+ for(j = 0;j < MaxChannels;j++)
+ Target[j] = 0.0f;
+ }
+
+ for(c = 0;c < num_channels;c++)
+ {
+ ALfloat *restrict Target = src->Direct.Mix.Gains[c].Target;
for(i = 0;i < (ALint)Device->NumChan;i++)
{
enum Channel chan = Device->Speaker2Chan[i];
if(chan == chans[c].channel)
{
- SrcMatrix[c][chan] = DryGain;
+ Target[chan] = DryGain;
break;
}
}
}
+
+ if(!src->Direct.Moving)
+ {
+ for(i = 0;i < num_channels;i++)
+ {
+ ALfloat *restrict Current = src->Direct.Mix.Gains[i].Current;
+ ALfloat *restrict Step = src->Direct.Mix.Gains[i].Step;
+ ALfloat *restrict Target = src->Direct.Mix.Gains[i].Target;
+ for(j = 0;j < MaxChannels;j++)
+ {
+ Current[j] = Target[j];
+ Step[j] = 1.0f;
+ }
+ }
+ src->Direct.Counter = 0;
+ src->Direct.Moving = AL_TRUE;
+ }
+ else
+ {
+ for(i = 0;i < num_channels;i++)
+ {
+ ALfloat *restrict Current = src->Direct.Mix.Gains[i].Current;
+ ALfloat *restrict Step = src->Direct.Mix.Gains[i].Step;
+ ALfloat *restrict Target = src->Direct.Mix.Gains[i].Target;
+ for(j = 0;j < MaxChannels;j++)
+ {
+ ALfloat cur = maxf(Current[j], FLT_EPSILON);
+ ALfloat trg = maxf(Target[j], FLT_EPSILON);
+ if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
+ Step[j] = powf(trg/cur, 1.0f/64.0f);
+ else
+ Step[j] = 1.0f;
+ Current[j] = cur;
+ }
+ }
+ src->Direct.Counter = 64;
+ }
+
+ src->IsHrtf = AL_FALSE;
+ src->Dry.Mix = SelectDirectMixer();
}
else if(Device->Hrtf)
{
@@ -428,12 +493,12 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
if(chans[c].channel == LFE)
{
/* Skip LFE */
- ALSource->Params.Direct.Hrtf.Params.Delay[c][0] = 0;
- ALSource->Params.Direct.Hrtf.Params.Delay[c][1] = 0;
+ src->Direct.Mix.Hrtf.Params[c].Delay[0] = 0;
+ src->Direct.Mix.Hrtf.Params[c].Delay[1] = 0;
for(i = 0;i < HRIR_LENGTH;i++)
{
- ALSource->Params.Direct.Hrtf.Params.Coeffs[c][i][0] = 0.0f;
- ALSource->Params.Direct.Hrtf.Params.Coeffs[c][i][1] = 0.0f;
+ src->Direct.Mix.Hrtf.Params[c].Coeffs[i][0] = 0.0f;
+ src->Direct.Mix.Hrtf.Params[c].Coeffs[i][1] = 0.0f;
}
}
else
@@ -441,75 +506,151 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
/* Get the static HRIR coefficients and delays for this
* channel. */
GetLerpedHrtfCoeffs(Device->Hrtf,
- 0.0f, chans[c].angle, DryGain,
- ALSource->Params.Direct.Hrtf.Params.Coeffs[c],
- ALSource->Params.Direct.Hrtf.Params.Delay[c]);
+ 0.0f, chans[c].angle, DryGain,
+ src->Direct.Mix.Hrtf.Params[c].Coeffs,
+ src->Direct.Mix.Hrtf.Params[c].Delay);
}
}
- ALSource->Hrtf.Counter = 0;
- ALSource->Params.Direct.Hrtf.Params.IrSize = GetHrtfIrSize(Device->Hrtf);
+ src->Direct.Counter = 0;
+ src->Direct.Moving = AL_TRUE;
+ src->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf);
- ALSource->Params.Direct.Hrtf.State = &ALSource->Hrtf;
+ src->IsHrtf = AL_TRUE;
+ src->Dry.HrtfMix = SelectHrtfMixer();
}
else
{
+ for(i = 0;i < num_channels;i++)
+ {
+ ALfloat *restrict Target = src->Direct.Mix.Gains[i].Target;
+ for(j = 0;j < MaxChannels;j++)
+ Target[j] = 0.0f;
+ }
+
DryGain *= lerp(1.0f, 1.0f/sqrtf((float)Device->NumChan), hwidth/F_PI);
for(c = 0;c < num_channels;c++)
{
+ ALfloat *restrict Target = src->Direct.Mix.Gains[c].Target;
/* Special-case LFE */
if(chans[c].channel == LFE)
{
- SrcMatrix[c][chans[c].channel] = DryGain;
+ Target[chans[c].channel] = DryGain;
continue;
}
- ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain,
- SrcMatrix[c]);
+ ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain, Target);
+ }
+
+ if(!src->Direct.Moving)
+ {
+ for(i = 0;i < num_channels;i++)
+ {
+ ALfloat *restrict Current = src->Direct.Mix.Gains[i].Current;
+ ALfloat *restrict Step = src->Direct.Mix.Gains[i].Step;
+ ALfloat *restrict Target = src->Direct.Mix.Gains[i].Target;
+ for(j = 0;j < MaxChannels;j++)
+ {
+ Current[j] = Target[j];
+ Step[j] = 1.0f;
+ }
+ }
+ src->Direct.Counter = 0;
+ src->Direct.Moving = AL_TRUE;
+ }
+ else
+ {
+ for(i = 0;i < num_channels;i++)
+ {
+ ALfloat *restrict Current = src->Direct.Mix.Gains[i].Current;
+ ALfloat *restrict Step = src->Direct.Mix.Gains[i].Step;
+ ALfloat *restrict Target = src->Direct.Mix.Gains[i].Target;
+ for(j = 0;j < MaxChannels;j++)
+ {
+ ALfloat trg = maxf(Target[j], FLT_EPSILON);
+ ALfloat cur = maxf(Current[j], FLT_EPSILON);
+ if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
+ Step[j] = powf(trg/cur, 1.0f/64.0f);
+ else
+ Step[j] = 1.0f;
+ Current[j] = cur;
+ }
+ }
+ src->Direct.Counter = 64;
}
- }
- ALSource->Params.Direct.OutBuffer = Device->DryBuffer;
- ALSource->Params.Direct.ClickRemoval = Device->ClickRemoval;
- ALSource->Params.Direct.PendingClicks = Device->PendingClicks;
+ src->IsHrtf = AL_FALSE;
+ src->Dry.Mix = SelectDirectMixer();
+ }
for(i = 0;i < NumSends;i++)
{
- ALeffectslot *Slot = ALSource->Send[i].Slot;
- if(!Slot && i == 0)
- Slot = Device->DefaultSlot;
- if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
+ src->Send[i].Gain.Target = WetGain[i];
+ if(!src->Send[i].Moving)
{
- ALSource->Params.Send[i].OutBuffer = NULL;
- ALSource->Params.Send[i].ClickRemoval = NULL;
- ALSource->Params.Send[i].PendingClicks = NULL;
+ src->Send[i].Gain.Current = src->Send[i].Gain.Target;
+ src->Send[i].Gain.Step = 1.0f;
+ src->Send[i].Counter = 0;
+ src->Send[i].Moving = AL_TRUE;
}
else
{
- ALSource->Params.Send[i].OutBuffer = Slot->WetBuffer;
- ALSource->Params.Send[i].ClickRemoval = Slot->ClickRemoval;
- ALSource->Params.Send[i].PendingClicks = Slot->PendingClicks;
+ ALfloat cur = maxf(src->Send[i].Gain.Current, FLT_EPSILON);
+ ALfloat trg = maxf(src->Send[i].Gain.Target, FLT_EPSILON);
+ if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
+ src->Send[i].Gain.Step = powf(trg/cur, 1.0f/64.0f);
+ else
+ src->Send[i].Gain.Step = 1.0f;
+ src->Send[i].Gain.Current = cur;
+ src->Send[i].Counter = 64;
}
- ALSource->Params.Send[i].Gain = WetGain[i];
}
+ src->WetMix = SelectSendMixer();
{
- ALfloat gain = maxf(0.01f, DryGainHF);
+ ALfloat gainhf = maxf(0.01f, DryGainHF);
+ ALfloat gainlf = maxf(0.01f, DryGainLF);
+ ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
+ ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
for(c = 0;c < num_channels;c++)
- ALfilterState_setParams(&ALSource->Params.Direct.LpFilter[c],
- ALfilterType_HighShelf, gain,
- (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
+ {
+ src->Direct.Filters[c].ActiveType = AF_None;
+ if(gainhf != 1.0f) src->Direct.Filters[c].ActiveType |= AF_LowPass;
+ if(gainlf != 1.0f) src->Direct.Filters[c].ActiveType |= AF_HighPass;
+ ALfilterState_setParams(
+ &src->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
+ hfscale, 0.0f
+ );
+ ALfilterState_setParams(
+ &src->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
+ lfscale, 0.0f
+ );
+ }
}
for(i = 0;i < NumSends;i++)
{
- ALfloat gain = maxf(0.01f, WetGainHF[i]);
+ ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
+ ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
+ ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
+ ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
for(c = 0;c < num_channels;c++)
- ALfilterState_setParams(&ALSource->Params.Send[i].LpFilter[c],
- ALfilterType_HighShelf, gain,
- (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
+ {
+ src->Send[i].Filters[c].ActiveType = AF_None;
+ if(gainhf != 1.0f) src->Send[i].Filters[c].ActiveType |= AF_LowPass;
+ if(gainlf != 1.0f) src->Send[i].Filters[c].ActiveType |= AF_HighPass;
+ ALfilterState_setParams(
+ &src->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
+ hfscale, 0.0f
+ );
+ ALfilterState_setParams(
+ &src->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
+ lfscale, 0.0f
+ );
+ }
}
}
-ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
+ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
{
ALCdevice *Device = ALContext->Device;
+ const ALsource *ALSource = src->Source;
ALfloat Velocity[3],Direction[3],Position[3],SourceToListener[3];
ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
@@ -526,9 +667,11 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALfloat DecayDistance[MAX_SENDS];
ALfloat DryGain;
ALfloat DryGainHF;
+ ALfloat DryGainLF;
ALboolean DryGainHFAuto;
ALfloat WetGain[MAX_SENDS];
ALfloat WetGainHF[MAX_SENDS];
+ ALfloat WetGainLF[MAX_SENDS];
ALboolean WetGainAuto;
ALboolean WetGainHFAuto;
enum Resampler Resampler;
@@ -538,8 +681,12 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALint i, j;
DryGainHF = 1.0f;
+ DryGainLF = 1.0f;
for(i = 0;i < MAX_SENDS;i++)
+ {
WetGainHF[i] = 1.0f;
+ WetGainLF[i] = 1.0f;
+ }
/* Get context/device properties */
DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
@@ -577,9 +724,7 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
WetGainHFAuto = ALSource->WetGainHFAuto;
RoomRolloffBase = ALSource->RoomRolloffFactor;
- ALSource->Params.Direct.OutBuffer = Device->DryBuffer;
- ALSource->Params.Direct.ClickRemoval = Device->ClickRemoval;
- ALSource->Params.Direct.PendingClicks = Device->PendingClicks;
+ src->Direct.OutBuffer = Device->DryBuffer;
for(i = 0;i < NumSends;i++)
{
ALeffectslot *Slot = ALSource->Send[i].Slot;
@@ -619,17 +764,9 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
}
if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
- {
- ALSource->Params.Send[i].OutBuffer = NULL;
- ALSource->Params.Send[i].ClickRemoval = NULL;
- ALSource->Params.Send[i].PendingClicks = NULL;
- }
+ src->Send[i].OutBuffer = NULL;
else
- {
- ALSource->Params.Send[i].OutBuffer = Slot->WetBuffer;
- ALSource->Params.Send[i].ClickRemoval = Slot->ClickRemoval;
- ALSource->Params.Send[i].PendingClicks = Slot->PendingClicks;
- }
+ src->Send[i].OutBuffer = Slot->WetBuffer;
}
/* Transform source to listener space (convert to head relative) */
@@ -792,12 +929,14 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
/* Apply gain and frequency filters */
- DryGain *= ALSource->DirectGain * ListenerGain;
- DryGainHF *= ALSource->DirectGainHF;
+ DryGain *= ALSource->Direct.Gain * ListenerGain;
+ DryGainHF *= ALSource->Direct.GainHF;
+ DryGainLF *= ALSource->Direct.GainLF;
for(i = 0;i < NumSends;i++)
{
WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
WetGainHF[i] *= ALSource->Send[i].GainHF;
+ WetGainLF[i] *= ALSource->Send[i].GainLF;
}
/* Calculate velocity-based doppler effect */
@@ -828,25 +967,20 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
/* Calculate fixed-point stepping value, based on the pitch, buffer
* frequency, and output frequency. */
Pitch = Pitch * ALBuffer->Frequency / Frequency;
- if(Pitch > 10.0f)
- ALSource->Params.Step = 10<<FRACTIONBITS;
+ if(Pitch > (ALfloat)MAX_PITCH)
+ src->Step = MAX_PITCH<<FRACTIONBITS;
else
{
- ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
- if(ALSource->Params.Step == 0)
- ALSource->Params.Step = 1;
+ src->Step = fastf2i(Pitch*FRACTIONONE);
+ if(src->Step == 0)
+ src->Step = 1;
}
- ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step);
+ src->Resample = SelectResampler(Resampler, src->Step);
break;
}
BufferListItem = BufferListItem->next;
}
- if(Device->Hrtf)
- ALSource->Params.DryMix = SelectHrtfMixer();
- else
- ALSource->Params.DryMix = SelectDirectMixer();
- ALSource->Params.WetMix = SelectSendMixer();
if(Device->Hrtf)
{
@@ -869,56 +1003,55 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
}
/* Check to see if the HRIR is already moving. */
- if(ALSource->Hrtf.Moving)
+ if(src->Direct.Moving)
{
/* Calculate the normalized HRTF transition factor (delta). */
- delta = CalcHrtfDelta(ALSource->Params.Direct.Hrtf.Params.Gain, DryGain,
- ALSource->Params.Direct.Hrtf.Params.Dir, Position);
+ delta = CalcHrtfDelta(src->Direct.Mix.Hrtf.Gain, DryGain,
+ src->Direct.Mix.Hrtf.Dir, Position);
/* If the delta is large enough, get the moving HRIR target
* coefficients, target delays, steppping values, and counter. */
if(delta > 0.001f)
{
- ALSource->Hrtf.Counter = GetMovingHrtfCoeffs(Device->Hrtf,
+ ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf,
ev, az, DryGain, delta,
- ALSource->Hrtf.Counter,
- ALSource->Params.Direct.Hrtf.Params.Coeffs[0],
- ALSource->Params.Direct.Hrtf.Params.Delay[0],
- ALSource->Params.Direct.Hrtf.Params.CoeffStep,
- ALSource->Params.Direct.Hrtf.Params.DelayStep);
- ALSource->Params.Direct.Hrtf.Params.Gain = DryGain;
- ALSource->Params.Direct.Hrtf.Params.Dir[0] = Position[0];
- ALSource->Params.Direct.Hrtf.Params.Dir[1] = Position[1];
- ALSource->Params.Direct.Hrtf.Params.Dir[2] = Position[2];
+ src->Direct.Counter,
+ src->Direct.Mix.Hrtf.Params[0].Coeffs,
+ src->Direct.Mix.Hrtf.Params[0].Delay,
+ src->Direct.Mix.Hrtf.Params[0].CoeffStep,
+ src->Direct.Mix.Hrtf.Params[0].DelayStep);
+ src->Direct.Counter = counter;
+ src->Direct.Mix.Hrtf.Gain = DryGain;
+ src->Direct.Mix.Hrtf.Dir[0] = Position[0];
+ src->Direct.Mix.Hrtf.Dir[1] = Position[1];
+ src->Direct.Mix.Hrtf.Dir[2] = Position[2];
}
}
else
{
/* Get the initial (static) HRIR coefficients and delays. */
GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, DryGain,
- ALSource->Params.Direct.Hrtf.Params.Coeffs[0],
- ALSource->Params.Direct.Hrtf.Params.Delay[0]);
- ALSource->Hrtf.Counter = 0;
- ALSource->Hrtf.Moving = AL_TRUE;
- ALSource->Params.Direct.Hrtf.Params.Gain = DryGain;
- ALSource->Params.Direct.Hrtf.Params.Dir[0] = Position[0];
- ALSource->Params.Direct.Hrtf.Params.Dir[1] = Position[1];
- ALSource->Params.Direct.Hrtf.Params.Dir[2] = Position[2];
+ src->Direct.Mix.Hrtf.Params[0].Coeffs,
+ src->Direct.Mix.Hrtf.Params[0].Delay);
+ src->Direct.Counter = 0;
+ src->Direct.Moving = AL_TRUE;
+ src->Direct.Mix.Hrtf.Gain = DryGain;
+ src->Direct.Mix.Hrtf.Dir[0] = Position[0];
+ src->Direct.Mix.Hrtf.Dir[1] = Position[1];
+ src->Direct.Mix.Hrtf.Dir[2] = Position[2];
}
- ALSource->Params.Direct.Hrtf.Params.IrSize = GetHrtfIrSize(Device->Hrtf);
+ src->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf);
- ALSource->Params.Direct.Hrtf.State = &ALSource->Hrtf;
+ src->IsHrtf = AL_TRUE;
+ src->Dry.HrtfMix = SelectHrtfMixer();
}
else
{
- ALfloat (*Matrix)[MaxChannels] = ALSource->Params.Direct.Gains;
+ ALfloat *restrict Target = src->Direct.Mix.Gains[0].Target;
ALfloat DirGain = 0.0f;
ALfloat AmbientGain;
- for(i = 0;i < MAX_INPUT_CHANNELS;i++)
- {
- for(j = 0;j < MaxChannels;j++)
- Matrix[i][j] = 0.0f;
- }
+ for(j = 0;j < MaxChannels;j++)
+ Target[j] = 0.0f;
/* Normalize the length, and compute panned gains. */
if(Distance > FLT_EPSILON)
@@ -930,7 +1063,7 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
DirGain = sqrtf(Position[0]*Position[0] + Position[2]*Position[2]);
ComputeAngleGains(Device, atan2f(Position[0], -Position[2]*ZScale), 0.0f,
- DryGain*DirGain, Matrix[0]);
+ DryGain*DirGain, Target);
}
/* Adjustment for vertical offsets. Not the greatest, but simple
@@ -939,25 +1072,99 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
for(i = 0;i < (ALint)Device->NumChan;i++)
{
enum Channel chan = Device->Speaker2Chan[i];
- Matrix[0][chan] = maxf(Matrix[0][chan], AmbientGain);
+ Target[chan] = maxf(Target[chan], AmbientGain);
}
+
+ if(!src->Direct.Moving)
+ {
+ ALfloat *restrict Current = src->Direct.Mix.Gains[0].Current;
+ ALfloat *restrict Step = src->Direct.Mix.Gains[0].Step;
+ for(j = 0;j < MaxChannels;j++)
+ {
+ Current[j] = Target[j];
+ Step[j] = 1.0f;
+ }
+ src->Direct.Counter = 0;
+ src->Direct.Moving = AL_TRUE;
+ }
+ else
+ {
+ ALfloat *restrict Current = src->Direct.Mix.Gains[0].Current;
+ ALfloat *restrict Step = src->Direct.Mix.Gains[0].Step;
+ for(j = 0;j < MaxChannels;j++)
+ {
+ ALfloat cur = maxf(Current[j], FLT_EPSILON);
+ ALfloat trg = maxf(Target[j], FLT_EPSILON);
+ if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
+ Step[j] = powf(trg/cur, 1.0f/64.0f);
+ else
+ Step[j] = 1.0f;
+ Current[j] = cur;
+ }
+ src->Direct.Counter = 64;
+ }
+
+ src->IsHrtf = AL_FALSE;
+ src->Dry.Mix = SelectDirectMixer();
}
for(i = 0;i < NumSends;i++)
- ALSource->Params.Send[i].Gain = WetGain[i];
-
+ {
+ src->Send[i].Gain.Target = WetGain[i];
+ if(!src->Send[i].Moving)
+ {
+ src->Send[i].Gain.Current = src->Send[i].Gain.Target;
+ src->Send[i].Gain.Step = 1.0f;
+ src->Send[i].Counter = 0;
+ src->Send[i].Moving = AL_TRUE;
+ }
+ else
+ {
+ ALfloat cur = maxf(src->Send[i].Gain.Current, FLT_EPSILON);
+ ALfloat trg = maxf(src->Send[i].Gain.Target, FLT_EPSILON);
+ if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
+ src->Send[i].Gain.Step = powf(trg/cur, 1.0f/64.0f);
+ else
+ src->Send[i].Gain.Step = 1.0f;
+ src->Send[i].Gain.Current = cur;
+ src->Send[i].Counter = 64;
+ }
+ }
+ src->WetMix = SelectSendMixer();
{
- ALfloat gain = maxf(0.01f, DryGainHF);
- ALfilterState_setParams(&ALSource->Params.Direct.LpFilter[0],
- ALfilterType_HighShelf, gain,
- (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
+ ALfloat gainhf = maxf(0.01f, DryGainHF);
+ ALfloat gainlf = maxf(0.01f, DryGainLF);
+ ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
+ ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
+ src->Direct.Filters[0].ActiveType = AF_None;
+ if(gainhf != 1.0f) src->Direct.Filters[0].ActiveType |= AF_LowPass;
+ if(gainlf != 1.0f) src->Direct.Filters[0].ActiveType |= AF_HighPass;
+ ALfilterState_setParams(
+ &src->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
+ hfscale, 0.0f
+ );
+ ALfilterState_setParams(
+ &src->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
+ lfscale, 0.0f
+ );
}
for(i = 0;i < NumSends;i++)
{
- ALfloat gain = maxf(0.01f, WetGainHF[i]);
- ALfilterState_setParams(&ALSource->Params.Send[i].LpFilter[0],
- ALfilterType_HighShelf, gain,
- (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
+ ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
+ ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
+ ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
+ ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
+ src->Send[i].Filters[0].ActiveType = AF_None;
+ if(gainhf != 1.0f) src->Send[i].Filters[0].ActiveType |= AF_LowPass;
+ if(gainlf != 1.0f) src->Send[i].Filters[0].ActiveType |= AF_HighPass;
+ ALfilterState_setParams(
+ &src->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
+ hfscale, 0.0f
+ );
+ ALfilterState_setParams(
+ &src->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
+ lfscale, 0.0f
+ );
}
}
@@ -987,11 +1194,10 @@ static inline ALubyte aluF2UB(ALfloat val)
{ return aluF2B(val)+128; }
#define DECL_TEMPLATE(T, func) \
-static int Write_##T(ALCdevice *device, T *restrict buffer, \
- ALuint SamplesToDo) \
+static void Write_##T(ALCdevice *device, ALvoid **buffer, ALuint SamplesToDo) \
{ \
ALfloat (*restrict DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
- ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
+ const ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
const ALuint *offsets = device->ChannelOffsets; \
ALuint i, j; \
\
@@ -1002,11 +1208,11 @@ static int Write_##T(ALCdevice *device, T *restrict buffer, \
if(offsets[j] == INVALID_OFFSET) \
continue; \
\
- out = buffer + offsets[j]; \
+ out = (T*)(*buffer) + offsets[j]; \
for(i = 0;i < SamplesToDo;i++) \
out[i*numchans] = func(DryBuffer[j][i]); \
} \
- return SamplesToDo*numchans*sizeof(T); \
+ *buffer = (char*)(*buffer) + SamplesToDo*numchans*sizeof(T); \
}
DECL_TEMPLATE(ALfloat, aluF2F)
@@ -1024,7 +1230,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
{
ALuint SamplesToDo;
ALeffectslot **slot, **slot_end;
- ALsource **src, **src_end;
+ ALactivesource **src, **src_end;
ALCcontext *ctx;
FPUCtl oldMode;
ALuint i, c;
@@ -1033,6 +1239,8 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
while(size > 0)
{
+ IncrementRef(&device->MixCount);
+
SamplesToDo = minu(size, BUFFERSIZE);
for(c = 0;c < MaxChannels;c++)
memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
@@ -1057,37 +1265,31 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
src_end = src + ctx->ActiveSourceCount;
while(src != src_end)
{
- if((*src)->state != AL_PLAYING)
+ ALsource *source = (*src)->Source;
+
+ if(source->state != AL_PLAYING && source->state != AL_PAUSED)
{
+ ALactivesource *temp = *(--src_end);
+ *src_end = *src;
+ *src = temp;
--(ctx->ActiveSourceCount);
- *src = *(--src_end);
continue;
}
- if(!DeferUpdates && (ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) ||
+ if(!DeferUpdates && (ExchangeInt(&source->NeedsUpdate, AL_FALSE) ||
UpdateSources))
- ALsource_Update(*src, ctx);
+ (*src)->Update(*src, ctx);
- MixSource(*src, device, SamplesToDo);
+ if(source->state != AL_PAUSED)
+ MixSource(*src, device, SamplesToDo);
src++;
}
/* effect slot processing */
- slot = ctx->ActiveEffectSlots;
- slot_end = slot + ctx->ActiveEffectSlotCount;
+ slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots);
+ slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots);
while(slot != slot_end)
{
- ALfloat offset = (*slot)->ClickRemoval[0];
- if(offset < (1.0f/32768.0f))
- offset = 0.0f;
- else for(i = 0;i < SamplesToDo;i++)
- {
- (*slot)->WetBuffer[0][i] += offset;
- offset -= offset * (1.0f/256.0f);
- }
- (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0];
- (*slot)->PendingClicks[0] = 0.0f;
-
if(!DeferUpdates && ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
V((*slot)->EffectState,update)(device, *slot);
@@ -1106,17 +1308,6 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
slot = &device->DefaultSlot;
if(*slot != NULL)
{
- ALfloat offset = (*slot)->ClickRemoval[0];
- if(offset < (1.0f/32768.0f))
- offset = 0.0f;
- else for(i = 0;i < SamplesToDo;i++)
- {
- (*slot)->WetBuffer[0][i] += offset;
- offset -= offset * (1.0f/256.0f);
- }
- (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0];
- (*slot)->PendingClicks[0] = 0.0f;
-
if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
V((*slot)->EffectState,update)(device, *slot);
@@ -1136,87 +1327,50 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
device->SamplesDone %= device->Frequency;
ALCdevice_Unlock(device);
- /* Click-removal. Could do better; this only really handles immediate
- * changes between updates where a predictive sample could be
- * generated. Delays caused by effects and HRTF aren't caught. */
- if(device->FmtChans == DevFmtStereo)
+ if(device->Bs2b)
{
- /* Assumes the first two channels are FrontLeft and FrontRight */
- for(c = 0;c < 2;c++)
- {
- ALfloat offset = device->ClickRemoval[c];
- if(offset < (1.0f/32768.0f))
- offset = 0.0f;
- else for(i = 0;i < SamplesToDo;i++)
- {
- device->DryBuffer[c][i] += offset;
- offset -= offset * (1.0f/256.0f);
- }
- device->ClickRemoval[c] = offset + device->PendingClicks[c];
- device->PendingClicks[c] = 0.0f;
- }
- if(device->Bs2b)
+ /* Apply binaural/crossfeed filter */
+ for(i = 0;i < SamplesToDo;i++)
{
float samples[2];
- for(i = 0;i < SamplesToDo;i++)
- {
- samples[0] = device->DryBuffer[FrontLeft][i];
- samples[1] = device->DryBuffer[FrontRight][i];
- bs2b_cross_feed(device->Bs2b, samples);
- device->DryBuffer[FrontLeft][i] = samples[0];
- device->DryBuffer[FrontRight][i] = samples[1];
- }
- }
- }
- else
- {
- for(c = 0;c < MaxChannels;c++)
- {
- ALfloat offset = device->ClickRemoval[c];
- if(offset < (1.0f/32768.0f))
- offset = 0.0f;
- else for(i = 0;i < SamplesToDo;i++)
- {
- device->DryBuffer[c][i] += offset;
- offset -= offset * (1.0f/256.0f);
- }
- device->ClickRemoval[c] = offset + device->PendingClicks[c];
- device->PendingClicks[c] = 0.0f;
+ samples[0] = device->DryBuffer[FrontLeft][i];
+ samples[1] = device->DryBuffer[FrontRight][i];
+ bs2b_cross_feed(device->Bs2b, samples);
+ device->DryBuffer[FrontLeft][i] = samples[0];
+ device->DryBuffer[FrontRight][i] = samples[1];
}
}
if(buffer)
{
- int bytes = 0;
switch(device->FmtType)
{
case DevFmtByte:
- bytes = Write_ALbyte(device, buffer, SamplesToDo);
+ Write_ALbyte(device, &buffer, SamplesToDo);
break;
case DevFmtUByte:
- bytes = Write_ALubyte(device, buffer, SamplesToDo);
+ Write_ALubyte(device, &buffer, SamplesToDo);
break;
case DevFmtShort:
- bytes = Write_ALshort(device, buffer, SamplesToDo);
+ Write_ALshort(device, &buffer, SamplesToDo);
break;
case DevFmtUShort:
- bytes = Write_ALushort(device, buffer, SamplesToDo);
+ Write_ALushort(device, &buffer, SamplesToDo);
break;
case DevFmtInt:
- bytes = Write_ALint(device, buffer, SamplesToDo);
+ Write_ALint(device, &buffer, SamplesToDo);
break;
case DevFmtUInt:
- bytes = Write_ALuint(device, buffer, SamplesToDo);
+ Write_ALuint(device, &buffer, SamplesToDo);
break;
case DevFmtFloat:
- bytes = Write_ALfloat(device, buffer, SamplesToDo);
+ Write_ALfloat(device, &buffer, SamplesToDo);
break;
}
-
- buffer = (ALubyte*)buffer + bytes;
}
size -= SamplesToDo;
+ IncrementRef(&device->MixCount);
}
RestoreFPUMode(&oldMode);
@@ -1232,18 +1386,19 @@ ALvoid aluHandleDisconnect(ALCdevice *device)
Context = device->ContextList;
while(Context)
{
- ALsource **src, **src_end;
+ ALactivesource **src, **src_end;
src = Context->ActiveSources;
src_end = src + Context->ActiveSourceCount;
while(src != src_end)
{
- if((*src)->state == AL_PLAYING)
+ ALsource *source = (*src)->Source;
+ if(source->state == AL_PLAYING)
{
- (*src)->state = AL_STOPPED;
- (*src)->BuffersPlayed = (*src)->BuffersInQueue;
- (*src)->position = 0;
- (*src)->position_fraction = 0;
+ source->state = AL_STOPPED;
+ source->current_buffer = NULL;
+ source->position = 0;
+ source->position_fraction = 0;
}
src++;
}
diff --git a/Alc/alcConfig.c b/Alc/alcConfig.c
index 98c0df32..2c9aef41 100644
--- a/Alc/alcConfig.c
+++ b/Alc/alcConfig.c
@@ -32,13 +32,14 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
-
-#include "alMain.h"
-
#ifdef _WIN32_IE
#include <shlobj.h>
#endif
+#include "alMain.h"
+#include "compat.h"
+
+
typedef struct ConfigEntry {
char *key;
char *value;
@@ -48,10 +49,8 @@ typedef struct ConfigBlock {
ConfigEntry *entries;
unsigned int entryCount;
} ConfigBlock;
-
static ConfigBlock cfgBlock;
-static char buffer[1024];
static char *lstrip(char *line)
{
@@ -69,23 +68,132 @@ static char *rstrip(char *line)
return line;
}
+static int readline(FILE *f, char **output, size_t *maxlen)
+{
+ size_t len = 0;
+ int c;
+
+ while((c=fgetc(f)) != EOF && (c == '\r' || c == '\n'))
+ ;
+ if(c == EOF)
+ return 0;
+
+ do {
+ if(len+1 >= *maxlen)
+ {
+ void *temp = NULL;
+ size_t newmax;
+
+ newmax = (*maxlen ? (*maxlen)<<1 : 32);
+ if(newmax > *maxlen)
+ temp = realloc(*output, newmax);
+ if(!temp)
+ {
+ ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, *maxlen);
+ return 0;
+ }
+
+ *output = temp;
+ *maxlen = newmax;
+ }
+ (*output)[len++] = c;
+ (*output)[len] = '\0';
+ } while((c=fgetc(f)) != EOF && c != '\r' && c != '\n');
+
+ return 1;
+}
+
+
+static char *expdup(const char *str)
+{
+ char *output = NULL;
+ size_t maxlen = 0;
+ size_t len = 0;
+
+ while(*str != '\0')
+ {
+ const char *addstr;
+ size_t addstrlen;
+ size_t i;
+
+ if(str[0] != '$')
+ {
+ const char *next = strchr(str, '$');
+ addstr = str;
+ addstrlen = next ? (size_t)(next-str) : strlen(str);
+
+ str += addstrlen;
+ }
+ else
+ {
+ str++;
+ if(*str == '$')
+ {
+ const char *next = strchr(str+1, '$');
+ addstr = str;
+ addstrlen = next ? (size_t)(next-str) : strlen(str);
+
+ str += addstrlen;
+ }
+ else
+ {
+ char envname[1024];
+ size_t k = 0;
+
+ while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1)
+ envname[k++] = *(str++);
+ envname[k++] = '\0';
+
+ if((addstr=getenv(envname)) == NULL)
+ continue;
+ addstrlen = strlen(addstr);
+ }
+ }
+ if(addstrlen == 0)
+ continue;
+
+ if(addstrlen >= maxlen-len)
+ {
+ void *temp = NULL;
+ size_t newmax;
+
+ newmax = len+addstrlen+1;
+ if(newmax > maxlen)
+ temp = realloc(output, newmax);
+ if(!temp)
+ {
+ ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, maxlen);
+ return output;
+ }
+
+ output = temp;
+ maxlen = newmax;
+ }
+
+ for(i = 0;i < addstrlen;i++)
+ output[len++] = addstr[i];
+ output[len] = '\0';
+ }
+
+ return output ? output : calloc(1, 1);
+}
+
+
static void LoadConfigFromFile(FILE *f)
{
char curSection[128] = "";
+ char *buffer = NULL;
+ size_t maxlen = 0;
ConfigEntry *ent;
- while(fgets(buffer, sizeof(buffer), f))
+ while(readline(f, &buffer, &maxlen))
{
char *line, *comment;
char key[256] = "";
char value[256] = "";
comment = strchr(buffer, '#');
- if(comment)
- {
- *(comment++) = 0;
- comment = rstrip(lstrip(comment));
- }
+ if(comment) *(comment++) = 0;
line = rstrip(lstrip(buffer));
if(!line[0])
@@ -123,26 +231,26 @@ static void LoadConfigFromFile(FILE *f)
* manually. */
if(strcmp(value, "\"\"") == 0 || strcmp(value, "''") == 0)
value[0] = 0;
- }
- else if(sscanf(line, "%255[^=] %255[=]", key, value) == 2)
- {
- /* Special case for 'key =' */
- value[0] = 0;
- }
- else
- {
- ERR("config parse error: malformed option line: \"%s\"\n\n", line);
- continue;
- }
- rstrip(key);
-
- if(curSection[0] != 0)
- {
- size_t len = strlen(curSection);
- memmove(&key[len+1], key, sizeof(key)-1-len);
- key[len] = '/';
- memcpy(key, curSection, len);
- }
+ }
+ else if(sscanf(line, "%255[^=] %255[=]", key, value) == 2)
+ {
+ /* Special case for 'key =' */
+ value[0] = 0;
+ }
+ else
+ {
+ ERR("config parse error: malformed option line: \"%s\"\n\n", line);
+ continue;
+ }
+ rstrip(key);
+
+ if(curSection[0] != 0)
+ {
+ size_t len = strlen(curSection);
+ memmove(&key[len+1], key, sizeof(key)-1-len);
+ key[len] = '/';
+ memcpy(key, curSection, len);
+ }
/* Check if we already have this option set */
ent = cfgBlock.entries;
@@ -171,36 +279,57 @@ static void LoadConfigFromFile(FILE *f)
}
free(ent->value);
- ent->value = strdup(value);
+ ent->value = expdup(value);
TRACE("found '%s' = '%s'\n", ent->key, ent->value);
}
+
+ free(buffer);
}
+#ifdef _WIN32
void ReadALConfig(void)
{
- const char *str;
+ WCHAR buffer[PATH_MAX];
+ const WCHAR *str;
FILE *f;
-#ifdef _WIN32
- if(SHGetSpecialFolderPathA(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
+ if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
{
- size_t p = strlen(buffer);
- snprintf(buffer+p, sizeof(buffer)-p, "\\alsoft.ini");
+ size_t p = lstrlenW(buffer);
+ _snwprintf(buffer+p, PATH_MAX-p, L"\\alsoft.ini");
- TRACE("Loading config %s...\n", buffer);
- f = fopen(buffer, "rt");
+ TRACE("Loading config %ls...\n", buffer);
+ f = _wfopen(buffer, L"rt");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
+
+ if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str)
+ {
+ TRACE("Loading config %ls...\n", str);
+ f = _wfopen(str, L"rt");
+ if(f)
+ {
+ LoadConfigFromFile(f);
+ fclose(f);
+ }
+ }
+}
#else
+void ReadALConfig(void)
+{
+ char buffer[PATH_MAX];
+ const char *str;
+ FILE *f;
+
str = "/etc/openal/alsoft.conf";
TRACE("Loading config %s...\n", str);
- f = fopen(str, "r");
+ f = al_fopen(str, "r");
if(f)
{
LoadConfigFromFile(f);
@@ -231,7 +360,7 @@ void ReadALConfig(void)
buffer[sizeof(buffer)-1] = 0;
TRACE("Loading config %s...\n", next);
- f = fopen(next, "r");
+ f = al_fopen(next, "r");
if(f)
{
LoadConfigFromFile(f);
@@ -247,7 +376,7 @@ void ReadALConfig(void)
snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", str);
TRACE("Loading config %s...\n", buffer);
- f = fopen(buffer, "r");
+ f = al_fopen(buffer, "r");
if(f)
{
LoadConfigFromFile(f);
@@ -266,19 +395,18 @@ void ReadALConfig(void)
if(buffer[0] != 0)
{
TRACE("Loading config %s...\n", buffer);
- f = fopen(buffer, "r");
+ f = al_fopen(buffer, "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
-#endif
if((str=getenv("ALSOFT_CONF")) != NULL && *str)
{
TRACE("Loading config %s...\n", str);
- f = fopen(str, "r");
+ f = al_fopen(str, "r");
if(f)
{
LoadConfigFromFile(f);
@@ -286,6 +414,7 @@ void ReadALConfig(void)
}
}
}
+#endif
void FreeALConfig(void)
{
diff --git a/Alc/alcRing.c b/Alc/alcRing.c
index f831860f..9b5d8214 100644
--- a/Alc/alcRing.c
+++ b/Alc/alcRing.c
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include "alMain.h"
+#include "threads.h"
#include "compat.h"
@@ -35,7 +36,7 @@ struct RingBuffer {
ALint read_pos;
ALint write_pos;
- CRITICAL_SECTION cs;
+ almtx_t mtx;
};
@@ -51,7 +52,7 @@ RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length)
ring->read_pos = 0;
ring->write_pos = 0;
- InitializeCriticalSection(&ring->cs);
+ almtx_init(&ring->mtx, almtx_plain);
}
return ring;
}
@@ -60,7 +61,7 @@ void DestroyRingBuffer(RingBuffer *ring)
{
if(ring)
{
- DeleteCriticalSection(&ring->cs);
+ almtx_destroy(&ring->mtx);
free(ring);
}
}
@@ -69,9 +70,9 @@ ALsizei RingBufferSize(RingBuffer *ring)
{
ALsizei s;
- EnterCriticalSection(&ring->cs);
+ almtx_lock(&ring->mtx);
s = (ring->write_pos-ring->read_pos+ring->length) % ring->length;
- LeaveCriticalSection(&ring->cs);
+ almtx_unlock(&ring->mtx);
return s;
}
@@ -80,7 +81,7 @@ void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
{
int remain;
- EnterCriticalSection(&ring->cs);
+ almtx_lock(&ring->mtx);
remain = (ring->read_pos-ring->write_pos-1+ring->length) % ring->length;
if(remain < len) len = remain;
@@ -103,14 +104,14 @@ void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
ring->write_pos %= ring->length;
}
- LeaveCriticalSection(&ring->cs);
+ almtx_unlock(&ring->mtx);
}
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
{
int remain;
- EnterCriticalSection(&ring->cs);
+ almtx_lock(&ring->mtx);
remain = ring->length - ring->read_pos;
if(remain < len)
@@ -124,5 +125,5 @@ void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
ring->read_pos += len;
ring->read_pos %= ring->length;
- LeaveCriticalSection(&ring->cs);
+ almtx_unlock(&ring->mtx);
}
diff --git a/Alc/alstring.h b/Alc/alstring.h
new file mode 100644
index 00000000..5b37a483
--- /dev/null
+++ b/Alc/alstring.h
@@ -0,0 +1,48 @@
+#ifndef ALSTRING_H
+#define ALSTRING_H
+
+#include <string.h>
+
+#include "vector.h"
+
+
+typedef char al_string_char_type;
+DECL_VECTOR(al_string_char_type)
+
+typedef vector_al_string_char_type al_string;
+typedef const_vector_al_string_char_type const_al_string;
+
+#define AL_STRING_INIT(_x) VECTOR_INIT(_x)
+#define AL_STRING_DEINIT(_x) VECTOR_DEINIT(_x)
+
+inline ALsizei al_string_length(const_al_string str)
+{ return VECTOR_SIZE(str); }
+
+inline ALboolean al_string_empty(const_al_string str)
+{ return al_string_length(str) == 0; }
+
+inline const al_string_char_type *al_string_get_cstr(const_al_string str)
+{ return str ? &VECTOR_FRONT(str) : ""; }
+
+void al_string_clear(al_string *str);
+
+int al_string_cmp(const_al_string str1, const_al_string str2);
+int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2);
+
+void al_string_copy(al_string *str, const_al_string from);
+void al_string_copy_cstr(al_string *str, const al_string_char_type *from);
+
+void al_string_append_char(al_string *str, const al_string_char_type c);
+void al_string_append_cstr(al_string *str, const al_string_char_type *from);
+void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to);
+
+#ifdef _WIN32
+#include <wchar.h>
+/* Windows-only methods to deal with WideChar strings. */
+void al_string_copy_wcstr(al_string *str, const wchar_t *from);
+#endif
+
+
+DECL_VECTOR(al_string)
+
+#endif /* ALSTRING_H */
diff --git a/Alc/atomic.h b/Alc/atomic.h
deleted file mode 100644
index 1dd8f9dc..00000000
--- a/Alc/atomic.h
+++ /dev/null
@@ -1,180 +0,0 @@
-#ifndef AL_ATOMIC_H
-#define AL_ATOMIC_H
-
-
-typedef void *volatile XchgPtr;
-
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
-typedef unsigned int RefCount;
-inline RefCount IncrementRef(volatile RefCount *ptr)
-{ return __sync_add_and_fetch(ptr, 1); }
-inline RefCount DecrementRef(volatile RefCount *ptr)
-{ return __sync_sub_and_fetch(ptr, 1); }
-
-inline int ExchangeInt(volatile int *ptr, int newval)
-{
- return __sync_lock_test_and_set(ptr, newval);
-}
-inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{
- return __sync_lock_test_and_set(ptr, newval);
-}
-inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
-{
- return __sync_bool_compare_and_swap(ptr, oldval, newval);
-}
-inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
-{
- return __sync_bool_compare_and_swap(ptr, oldval, newval);
-}
-
-#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-
-inline unsigned int xaddl(volatile unsigned int *dest, int incr)
-{
- unsigned int ret;
- __asm__ __volatile__("lock; xaddl %0,(%1)"
- : "=r" (ret)
- : "r" (dest), "0" (incr)
- : "memory");
- return ret;
-}
-
-typedef unsigned int RefCount;
-inline RefCount IncrementRef(volatile RefCount *ptr)
-{ return xaddl(ptr, 1)+1; }
-inline RefCount DecrementRef(volatile RefCount *ptr)
-{ return xaddl(ptr, -1)-1; }
-
-inline int ExchangeInt(volatile int *dest, int newval)
-{
- int ret;
- __asm__ __volatile__("lock; xchgl %0,(%1)"
- : "=r" (ret)
- : "r" (dest), "0" (newval)
- : "memory");
- return ret;
-}
-
-inline ALboolean CompExchangeInt(volatile int *dest, int oldval, int newval)
-{
- int ret;
- __asm__ __volatile__("lock; cmpxchgl %2,(%1)"
- : "=a" (ret)
- : "r" (dest), "r" (newval), "0" (oldval)
- : "memory");
- return ret == oldval;
-}
-
-inline void *ExchangePtr(XchgPtr *dest, void *newval)
-{
- void *ret;
- __asm__ __volatile__(
-#ifdef __i386__
- "lock; xchgl %0,(%1)"
-#else
- "lock; xchgq %0,(%1)"
-#endif
- : "=r" (ret)
- : "r" (dest), "0" (newval)
- : "memory"
- );
- return ret;
-}
-
-inline ALboolean CompExchangePtr(XchgPtr *dest, void *oldval, void *newval)
-{
- void *ret;
- __asm__ __volatile__(
-#ifdef __i386__
- "lock; cmpxchgl %2,(%1)"
-#else
- "lock; cmpxchgq %2,(%1)"
-#endif
- : "=a" (ret)
- : "r" (dest), "r" (newval), "0" (oldval)
- : "memory"
- );
- return ret == oldval;
-}
-
-#elif defined(_WIN32)
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-typedef LONG RefCount;
-inline RefCount IncrementRef(volatile RefCount *ptr)
-{ return InterlockedIncrement(ptr); }
-inline RefCount DecrementRef(volatile RefCount *ptr)
-{ return InterlockedDecrement(ptr); }
-
-extern ALbyte LONG_size_does_not_match_int[(sizeof(LONG)==sizeof(int))?1:-1];
-
-inline int ExchangeInt(volatile int *ptr, int newval)
-{
- union {
- volatile int *i;
- volatile LONG *l;
- } u = { ptr };
- return InterlockedExchange(u.l, newval);
-}
-inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{
- return InterlockedExchangePointer(ptr, newval);
-}
-inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
-{
- union {
- volatile int *i;
- volatile LONG *l;
- } u = { ptr };
- return InterlockedCompareExchange(u.l, newval, oldval) == oldval;
-}
-inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
-{
- return InterlockedCompareExchangePointer(ptr, newval, oldval) == oldval;
-}
-
-#elif defined(__APPLE__)
-
-#include <libkern/OSAtomic.h>
-
-typedef int32_t RefCount;
-inline RefCount IncrementRef(volatile RefCount *ptr)
-{ return OSAtomicIncrement32Barrier(ptr); }
-inline RefCount DecrementRef(volatile RefCount *ptr)
-{ return OSAtomicDecrement32Barrier(ptr); }
-
-inline int ExchangeInt(volatile int *ptr, int newval)
-{
- /* Really? No regular old atomic swap? */
- int oldval;
- do {
- oldval = *ptr;
- } while(!OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr));
- return oldval;
-}
-inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{
- void *oldval;
- do {
- oldval = *ptr;
- } while(!OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr));
- return oldval;
-}
-inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
-{
- return OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr);
-}
-inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
-{
- return OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr);
-}
-
-#else
-#error "No atomic functions available on this platform!"
-typedef ALuint RefCount;
-#endif
-
-#endif /* AL_ATOMIC_H */
diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c
index 874b31c3..0712a412 100644
--- a/Alc/backends/alsa.c
+++ b/Alc/backends/alsa.c
@@ -227,14 +227,27 @@ static ALCboolean alsa_load(void)
typedef struct {
- ALCchar *name;
- char *device;
+ al_string name;
+ al_string device_name;
} DevMap;
+DECL_VECTOR(DevMap)
-static DevMap *allDevNameMap;
-static ALuint numDevNames;
-static DevMap *allCaptureDevNameMap;
-static ALuint numCaptureDevNames;
+static vector_DevMap PlaybackDevices;
+static vector_DevMap CaptureDevices;
+
+static void clear_devlist(vector_DevMap *devlist)
+{
+ DevMap *iter, *end;
+
+ iter = VECTOR_ITER_BEGIN(*devlist);
+ end = VECTOR_ITER_END(*devlist);
+ for(;iter != end;iter++)
+ {
+ AL_STRING_DEINIT(iter->name);
+ AL_STRING_DEINIT(iter->device_name);
+ }
+ VECTOR_RESIZE(*devlist, 0);
+}
static const char *prefix_name(snd_pcm_stream_t stream)
@@ -243,23 +256,26 @@ static const char *prefix_name(snd_pcm_stream_t stream)
return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix";
}
-static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
+static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
{
const char *main_prefix = "plughw:";
snd_ctl_t *handle;
- int card, err, dev, idx;
snd_ctl_card_info_t *info;
snd_pcm_info_t *pcminfo;
- DevMap *DevList;
+ int card, err, dev;
+ DevMap entry;
+
+ clear_devlist(DeviceList);
snd_ctl_card_info_malloc(&info);
snd_pcm_info_malloc(&pcminfo);
- DevList = malloc(sizeof(DevMap) * 1);
- DevList[0].name = strdup(alsaDevice);
- DevList[0].device = strdup(GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
- "device" : "capture", "default"));
- idx = 1;
+ AL_STRING_INIT(entry.name);
+ AL_STRING_INIT(entry.device_name);
+ al_string_copy_cstr(&entry.name, alsaDevice);
+ al_string_copy_cstr(&entry.device_name, GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
+ "device" : "capture", "default"));
+ VECTOR_PUSH_BACK(*DeviceList, entry);
card = -1;
if((err=snd_card_next(&card)) < 0)
@@ -293,8 +309,9 @@ static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
dev = -1;
while(1)
{
+ const char *device_prefix = card_prefix;
const char *devname;
- void *temp;
+ char device[128];
if(snd_ctl_pcm_next_device(handle, &dev) < 0)
ERR("snd_ctl_pcm_next_device failed\n");
@@ -310,28 +327,22 @@ static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
continue;
}
- temp = realloc(DevList, sizeof(DevMap) * (idx+1));
- if(temp)
- {
- const char *device_prefix = card_prefix;
- char device[128];
-
- DevList = temp;
- devname = snd_pcm_info_get_name(pcminfo);
+ devname = snd_pcm_info_get_name(pcminfo);
- snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
- ConfigValueStr("alsa", name, &device_prefix);
+ snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
+ ConfigValueStr("alsa", name, &device_prefix);
- snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
- cardname, devname, cardid, dev);
- snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
- device_prefix, cardid, dev);
+ snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
+ cardname, devname, cardid, dev);
+ snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
+ device_prefix, cardid, dev);
- TRACE("Got device \"%s\", \"%s\"\n", name, device);
- DevList[idx].name = strdup(name);
- DevList[idx].device = strdup(device);
- idx++;
- }
+ TRACE("Got device \"%s\", \"%s\"\n", name, device);
+ AL_STRING_INIT(entry.name);
+ AL_STRING_INIT(entry.device_name);
+ al_string_copy_cstr(&entry.name, name);
+ al_string_copy_cstr(&entry.device_name, device);
+ VECTOR_PUSH_BACK(*DeviceList, entry);
}
snd_ctl_close(handle);
next_card:
@@ -343,9 +354,6 @@ static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
snd_pcm_info_free(pcminfo);
snd_ctl_card_info_free(info);
-
- *count = idx;
- return DevList;
}
@@ -390,12 +398,11 @@ typedef struct ALCplaybackAlsa {
ALsizei size;
volatile int killNow;
- althread_t thread;
+ althrd_t thread;
} ALCplaybackAlsa;
-DECLARE_ALCBACKEND_VTABLE(ALCplaybackAlsa);
-static ALuint ALCplaybackAlsa_mixerProc(ALvoid *ptr);
-static ALuint ALCplaybackAlsa_mixerNoMMapProc(ALvoid *ptr);
+static int ALCplaybackAlsa_mixerProc(void *ptr);
+static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr);
static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device);
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, Destruct)
@@ -406,8 +413,12 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self);
static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self);
static DECLARE_FORWARD2(ALCplaybackAlsa, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, ALCuint, availableSamples)
+static ALint64 ALCplaybackAlsa_getLatency(ALCplaybackAlsa *self);
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCplaybackAlsa)
+
+DEFINE_ALCBACKEND_VTABLE(ALCplaybackAlsa);
static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device)
@@ -417,7 +428,7 @@ static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device)
}
-static ALuint ALCplaybackAlsa_mixerProc(ALvoid *ptr)
+static int ALCplaybackAlsa_mixerProc(void *ptr)
{
ALCplaybackAlsa *self = (ALCplaybackAlsa*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -429,7 +440,7 @@ static ALuint ALCplaybackAlsa_mixerProc(ALvoid *ptr)
int err;
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
update_size = device->UpdateSize;
num_updates = device->NumUpdates;
@@ -509,7 +520,7 @@ static ALuint ALCplaybackAlsa_mixerProc(ALvoid *ptr)
return 0;
}
-static ALuint ALCplaybackAlsa_mixerNoMMapProc(ALvoid *ptr)
+static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr)
{
ALCplaybackAlsa *self = (ALCplaybackAlsa*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -519,7 +530,7 @@ static ALuint ALCplaybackAlsa_mixerNoMMapProc(ALvoid *ptr)
int err;
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
update_size = device->UpdateSize;
num_updates = device->NumUpdates;
@@ -614,20 +625,22 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
if(name)
{
- size_t idx;
+ const DevMap *iter, *end;
- if(!allDevNameMap)
- allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
+ if(VECTOR_SIZE(PlaybackDevices) == 0)
+ probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
- for(idx = 0;idx < numDevNames;idx++)
+ iter = VECTOR_ITER_BEGIN(PlaybackDevices);
+ end = VECTOR_ITER_END(PlaybackDevices);
+ for(;iter != end;iter++)
{
- if(strcmp(name, allDevNameMap[idx].name) == 0)
+ if(al_string_cmp_cstr(iter->name, name) == 0)
{
- driver = allDevNameMap[idx].device;
+ driver = al_string_get_cstr(iter->device_name);
break;
}
}
- if(idx == numDevNames)
+ if(iter == end)
return ALC_INVALID_VALUE;
}
else
@@ -636,6 +649,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
driver = GetConfigValue("alsa", "device", "default");
}
+ TRACE("Opening device \"%s\"\n", driver);
err = snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if(err < 0)
{
@@ -646,7 +660,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
/* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
snd_config_update_free_global();
- device->DeviceName = strdup(name);
+ al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
@@ -663,15 +677,14 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
unsigned int periodLen, bufferLen;
snd_pcm_sw_params_t *sp = NULL;
snd_pcm_hw_params_t *hp = NULL;
+ snd_pcm_format_t format = -1;
snd_pcm_access_t access;
- snd_pcm_format_t format;
unsigned int periods;
unsigned int rate;
const char *funcerr;
int allowmmap;
int err;
- format = -1;
switch(device->FmtType)
{
case DevFmtByte:
@@ -809,7 +822,7 @@ error:
static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- ALuint (*thread_func)(ALvoid*) = NULL;
+ int (*thread_func)(void*) = NULL;
snd_pcm_hw_params_t *hp = NULL;
snd_pcm_access_t access;
const char *funcerr;
@@ -845,7 +858,8 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
}
thread_func = ALCplaybackAlsa_mixerProc;
}
- if(!StartThread(&self->thread, thread_func, self))
+ self->killNow = 0;
+ if(althrd_create(&self->thread, thread_func, self) != althrd_success)
{
ERR("Could not create playback thread\n");
free(self->buffer);
@@ -863,13 +877,14 @@ error:
static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self)
{
- if(self->thread)
- {
- self->killNow = 1;
- StopThread(self->thread);
- self->thread = NULL;
- }
- self->killNow = 0;
+ int res;
+
+ if(self->killNow)
+ return;
+
+ self->killNow = 1;
+ althrd_join(self->thread, &res);
+
free(self->buffer);
self->buffer = NULL;
}
@@ -889,14 +904,6 @@ static ALint64 ALCplaybackAlsa_getLatency(ALCplaybackAlsa *self)
}
-static void ALCplaybackAlsa_Delete(ALCplaybackAlsa *self)
-{
- free(self);
-}
-
-DEFINE_ALCBACKEND_VTABLE(ALCplaybackAlsa);
-
-
typedef struct ALCcaptureAlsa {
DERIVE_FROM_TYPE(ALCbackend);
@@ -910,7 +917,6 @@ typedef struct ALCcaptureAlsa {
snd_pcm_sframes_t last_avail;
} ALCcaptureAlsa;
-DECLARE_ALCBACKEND_VTABLE(ALCcaptureAlsa);
static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device);
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, Destruct)
@@ -921,8 +927,12 @@ static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self);
static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self);
static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self);
+static ALint64 ALCcaptureAlsa_getLatency(ALCcaptureAlsa *self);
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCcaptureAlsa)
+
+DEFINE_ALCBACKEND_VTABLE(ALCcaptureAlsa);
static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device)
@@ -940,26 +950,28 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
snd_pcm_uframes_t bufferSizeInFrames;
snd_pcm_uframes_t periodSizeInFrames;
ALboolean needring = AL_FALSE;
- snd_pcm_format_t format;
+ snd_pcm_format_t format = -1;
const char *funcerr;
int err;
if(name)
{
- size_t idx;
+ const DevMap *iter, *end;
- if(!allCaptureDevNameMap)
- allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
+ if(VECTOR_SIZE(CaptureDevices) == 0)
+ probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
- for(idx = 0;idx < numCaptureDevNames;idx++)
+ iter = VECTOR_ITER_BEGIN(CaptureDevices);
+ end = VECTOR_ITER_END(CaptureDevices);
+ for(;iter != end;iter++)
{
- if(strcmp(name, allCaptureDevNameMap[idx].name) == 0)
+ if(al_string_cmp_cstr(iter->name, name) == 0)
{
- driver = allCaptureDevNameMap[idx].device;
+ driver = al_string_get_cstr(iter->device_name);
break;
}
}
- if(idx == numCaptureDevNames)
+ if(iter == end)
return ALC_INVALID_VALUE;
}
else
@@ -968,6 +980,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
driver = GetConfigValue("alsa", "capture", "default");
}
+ TRACE("Opening device \"%s\"\n", driver);
err = snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
if(err < 0)
{
@@ -978,7 +991,6 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
/* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
snd_config_update_free_global();
- format = -1;
switch(device->FmtType)
{
case DevFmtByte:
@@ -1056,7 +1068,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
}
}
- device->DeviceName = strdup(name);
+ al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
@@ -1114,11 +1126,12 @@ static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self)
void *ptr;
size = snd_pcm_frames_to_bytes(self->pcmHandle, avail);
- ptr = realloc(self->buffer, size);
+ ptr = malloc(size);
if(ptr)
{
+ ALCcaptureAlsa_captureSamples(self, ptr, avail);
+ free(self->buffer);
self->buffer = ptr;
- ALCcaptureAlsa_captureSamples(self, self->buffer, avail);
self->size = size;
}
}
@@ -1150,7 +1163,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff
if((snd_pcm_uframes_t)amt > samples) amt = samples;
amt = snd_pcm_frames_to_bytes(self->pcmHandle, amt);
- memmove(buffer, self->buffer, amt);
+ memcpy(buffer, self->buffer, amt);
if(self->size > amt)
{
@@ -1287,14 +1300,11 @@ static ALint64 ALCcaptureAlsa_getLatency(ALCcaptureAlsa *self)
return maxi64((ALint64)delay*1000000000/device->Frequency, 0);
}
-static void ALCcaptureAlsa_Delete(ALCcaptureAlsa *self)
-{
- free(self);
-}
-
-DEFINE_ALCBACKEND_VTABLE(ALCcaptureAlsa);
-
+static inline void AppendAllDevicesList2(const DevMap *entry)
+{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
+static inline void AppendCaptureDeviceList2(const DevMap *entry)
+{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
typedef struct ALCalsaBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
@@ -1303,6 +1313,9 @@ typedef struct ALCalsaBackendFactory {
static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self))
{
+ VECTOR_INIT(PlaybackDevices);
+ VECTOR_INIT(CaptureDevices);
+
if(!alsa_load())
return ALC_FALSE;
return ALC_TRUE;
@@ -1310,25 +1323,11 @@ static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self)
static void ALCalsaBackendFactory_deinit(ALCalsaBackendFactory* UNUSED(self))
{
- ALuint i;
-
- for(i = 0;i < numDevNames;++i)
- {
- free(allDevNameMap[i].name);
- free(allDevNameMap[i].device);
- }
- free(allDevNameMap);
- allDevNameMap = NULL;
- numDevNames = 0;
+ clear_devlist(&PlaybackDevices);
+ VECTOR_DEINIT(PlaybackDevices);
- for(i = 0;i < numCaptureDevNames;++i)
- {
- free(allCaptureDevNameMap[i].name);
- free(allCaptureDevNameMap[i].device);
- }
- free(allCaptureDevNameMap);
- allCaptureDevNameMap = NULL;
- numCaptureDevNames = 0;
+ clear_devlist(&CaptureDevices);
+ VECTOR_DEINIT(CaptureDevices);
#ifdef HAVE_DYNLOAD
if(alsa_handle)
@@ -1346,36 +1345,16 @@ static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUS
static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type)
{
- ALuint i;
-
switch(type)
{
case ALL_DEVICE_PROBE:
- for(i = 0;i < numDevNames;++i)
- {
- free(allDevNameMap[i].name);
- free(allDevNameMap[i].device);
- }
-
- free(allDevNameMap);
- allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
-
- for(i = 0;i < numDevNames;++i)
- AppendAllDevicesList(allDevNameMap[i].name);
+ probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
+ VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
- for(i = 0;i < numCaptureDevNames;++i)
- {
- free(allCaptureDevNameMap[i].name);
- free(allCaptureDevNameMap[i].device);
- }
-
- free(allCaptureDevNameMap);
- allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
-
- for(i = 0;i < numCaptureDevNames;++i)
- AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
+ probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
+ VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
break;
}
}
@@ -1386,8 +1365,9 @@ static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UN
{
ALCplaybackAlsa *backend;
- backend = calloc(1, sizeof(*backend));
+ backend = ALCplaybackAlsa_New(sizeof(*backend));
if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
ALCplaybackAlsa_Construct(backend, device);
@@ -1397,8 +1377,9 @@ static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UN
{
ALCcaptureAlsa *backend;
- backend = calloc(1, sizeof(*backend));
+ backend = ALCcaptureAlsa_New(sizeof(*backend));
if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
ALCcaptureAlsa_Construct(backend, device);
diff --git a/Alc/backends/base.c b/Alc/backends/base.c
index fe797562..37e4ccc9 100644
--- a/Alc/backends/base.c
+++ b/Alc/backends/base.c
@@ -11,13 +11,15 @@
/* Base ALCbackend method implementations. */
void ALCbackend_Construct(ALCbackend *self, ALCdevice *device)
{
+ int ret;
self->mDevice = device;
- InitializeCriticalSection(&self->mMutex);
+ ret = almtx_init(&self->mMutex, almtx_recursive);
+ assert(ret == althrd_success);
}
void ALCbackend_Destruct(ALCbackend *self)
{
- DeleteCriticalSection(&self->mMutex);
+ almtx_destroy(&self->mMutex);
}
ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self))
@@ -42,12 +44,14 @@ ALint64 ALCbackend_getLatency(ALCbackend* UNUSED(self))
void ALCbackend_lock(ALCbackend *self)
{
- EnterCriticalSection(&self->mMutex);
+ int ret = almtx_lock(&self->mMutex);
+ assert(ret == althrd_success);
}
void ALCbackend_unlock(ALCbackend *self)
{
- LeaveCriticalSection(&self->mMutex);
+ int ret = almtx_unlock(&self->mMutex);
+ assert(ret == althrd_success);
}
@@ -60,9 +64,11 @@ void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self))
/* Wrappers to use an old-style backend with the new interface. */
typedef struct PlaybackWrapper {
DERIVE_FROM_TYPE(ALCbackend);
+
+ const BackendFuncs *Funcs;
} PlaybackWrapper;
-static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device);
+static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs);
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, Destruct)
static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name);
static void PlaybackWrapper_close(PlaybackWrapper *self);
@@ -74,62 +80,61 @@ static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples)
static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self);
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
-static void PlaybackWrapper_Delete(PlaybackWrapper *self);
+DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper)
DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper);
-static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device)
+static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(PlaybackWrapper, ALCbackend, self);
+
+ self->Funcs = funcs;
}
static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return device->Funcs->OpenPlayback(device, name);
+ return self->Funcs->OpenPlayback(device, name);
}
static void PlaybackWrapper_close(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- device->Funcs->ClosePlayback(device);
+ self->Funcs->ClosePlayback(device);
}
static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return device->Funcs->ResetPlayback(device);
+ return self->Funcs->ResetPlayback(device);
}
static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return device->Funcs->StartPlayback(device);
+ return self->Funcs->StartPlayback(device);
}
static void PlaybackWrapper_stop(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- device->Funcs->StopPlayback(device);
+ self->Funcs->StopPlayback(device);
}
static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return device->Funcs->GetLatency(device);
-}
-
-static void PlaybackWrapper_Delete(PlaybackWrapper *self)
-{
- free(self);
+ return self->Funcs->GetLatency(device);
}
typedef struct CaptureWrapper {
DERIVE_FROM_TYPE(ALCbackend);
+
+ const BackendFuncs *Funcs;
} CaptureWrapper;
-static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device);
+static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs);
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, Destruct)
static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name);
static void CaptureWrapper_close(CaptureWrapper *self);
@@ -141,75 +146,72 @@ static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self);
static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self);
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock)
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock)
-static void CaptureWrapper_Delete(CaptureWrapper *self);
+DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper)
DEFINE_ALCBACKEND_VTABLE(CaptureWrapper);
-static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device)
+static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(CaptureWrapper, ALCbackend, self);
+
+ self->Funcs = funcs;
}
static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return device->Funcs->OpenCapture(device, name);
+ return self->Funcs->OpenCapture(device, name);
}
static void CaptureWrapper_close(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- device->Funcs->CloseCapture(device);
+ self->Funcs->CloseCapture(device);
}
static ALCboolean CaptureWrapper_start(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- device->Funcs->StartCapture(device);
+ self->Funcs->StartCapture(device);
return ALC_TRUE;
}
static void CaptureWrapper_stop(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- device->Funcs->StopCapture(device);
+ self->Funcs->StopCapture(device);
}
static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return device->Funcs->CaptureSamples(device, buffer, samples);
+ return self->Funcs->CaptureSamples(device, buffer, samples);
}
static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return device->Funcs->AvailableSamples(device);
+ return self->Funcs->AvailableSamples(device);
}
static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return device->Funcs->GetLatency(device);
-}
-
-static void CaptureWrapper_Delete(CaptureWrapper *self)
-{
- free(self);
+ return self->Funcs->GetLatency(device);
}
-ALCbackend *create_backend_wrapper(ALCdevice *device, ALCbackend_Type type)
+ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
PlaybackWrapper *backend;
- backend = malloc(sizeof(*backend));
+ backend = PlaybackWrapper_New(sizeof(*backend));
if(!backend) return NULL;
- PlaybackWrapper_Construct(backend, device);
+ PlaybackWrapper_Construct(backend, device, funcs);
return STATIC_CAST(ALCbackend, backend);
}
@@ -218,10 +220,10 @@ ALCbackend *create_backend_wrapper(ALCdevice *device, ALCbackend_Type type)
{
CaptureWrapper *backend;
- backend = malloc(sizeof(*backend));
+ backend = CaptureWrapper_New(sizeof(*backend));
if(!backend) return NULL;
- CaptureWrapper_Construct(backend, device);
+ CaptureWrapper_Construct(backend, device, funcs);
return STATIC_CAST(ALCbackend, backend);
}
diff --git a/Alc/backends/base.h b/Alc/backends/base.h
index 1bbc1fb0..5573c178 100644
--- a/Alc/backends/base.h
+++ b/Alc/backends/base.h
@@ -2,7 +2,7 @@
#define AL_BACKENDS_BASE_H
#include "alMain.h"
-#include "compat.h"
+#include "threads.h"
struct ALCbackendVtable;
@@ -12,7 +12,7 @@ typedef struct ALCbackend {
ALCdevice *mDevice;
- CRITICAL_SECTION mMutex;
+ almtx_t mMutex;
} ALCbackend;
void ALCbackend_Construct(ALCbackend *self, ALCdevice *device);
@@ -42,12 +42,9 @@ struct ALCbackendVtable {
void (*const lock)(ALCbackend*);
void (*const unlock)(ALCbackend*);
- void (*const Delete)(ALCbackend*);
+ void (*const Delete)(void*);
};
-#define DECLARE_ALCBACKEND_VTABLE(T) \
-static const struct ALCbackendVtable T##_ALCbackend_vtable
-
#define DEFINE_ALCBACKEND_VTABLE(T) \
DECLARE_THUNK(T, ALCbackend, void, Destruct) \
DECLARE_THUNK1(T, ALCbackend, ALCenum, open, const ALCchar*) \
@@ -60,9 +57,10 @@ DECLARE_THUNK(T, ALCbackend, ALCuint, availableSamples) \
DECLARE_THUNK(T, ALCbackend, ALint64, getLatency) \
DECLARE_THUNK(T, ALCbackend, void, lock) \
DECLARE_THUNK(T, ALCbackend, void, unlock) \
-DECLARE_THUNK(T, ALCbackend, void, Delete) \
+static void T##_ALCbackend_Delete(void *ptr) \
+{ T##_Delete(STATIC_UPCAST(T, ALCbackend, (ALCbackend*)ptr)); } \
\
-DECLARE_ALCBACKEND_VTABLE(T) = { \
+static const struct ALCbackendVtable T##_ALCbackend_vtable = { \
T##_ALCbackend_Destruct, \
\
T##_ALCbackend_open, \
@@ -125,9 +123,11 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \
ALCbackendFactory *ALCpulseBackendFactory_getFactory(void);
ALCbackendFactory *ALCalsaBackendFactory_getFactory(void);
ALCbackendFactory *ALCossBackendFactory_getFactory(void);
+ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void);
+ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
ALCbackendFactory *ALCloopbackFactory_getFactory(void);
-ALCbackend *create_backend_wrapper(ALCdevice *device, ALCbackend_Type type);
+ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type);
#endif /* AL_BACKENDS_BASE_H */
diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c
index 5c9b69c8..b3583ffd 100644
--- a/Alc/backends/coreaudio.c
+++ b/Alc/backends/coreaudio.c
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <alloca.h>
#include "alMain.h"
#include "alu.h"
@@ -180,7 +181,7 @@ static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName)
return ALC_INVALID_VALUE;
}
- device->DeviceName = strdup(deviceName);
+ al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
}
@@ -577,6 +578,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
if(data->ring == NULL)
goto error;
+ al_string_copy_cstr(&device->DeviceName, deviceName);
+
return ALC_NO_ERROR;
error:
diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c
index 6b108fba..3ca398ed 100644
--- a/Alc/backends/dsound.c
+++ b/Alc/backends/dsound.c
@@ -36,6 +36,9 @@
#include "alu.h"
#include "threads.h"
#include "compat.h"
+#include "alstring.h"
+
+#include "backends/base.h"
#ifndef DSSPEAKER_5POINT1
# define DSSPEAKER_5POINT1 0x00000006
@@ -55,54 +58,23 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
+#ifdef HAVE_DYNLOAD
static void *ds_handle;
-static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter);
-static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext);
-static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter);
-static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext);
+static HRESULT (WINAPI *pDirectSoundCreate)(const GUID *pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter);
+static HRESULT (WINAPI *pDirectSoundEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext);
+static HRESULT (WINAPI *pDirectSoundCaptureCreate)(const GUID *pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter);
+static HRESULT (WINAPI *pDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext);
#define DirectSoundCreate pDirectSoundCreate
-#define DirectSoundEnumerateA pDirectSoundEnumerateA
+#define DirectSoundEnumerateW pDirectSoundEnumerateW
#define DirectSoundCaptureCreate pDirectSoundCaptureCreate
-#define DirectSoundCaptureEnumerateA pDirectSoundCaptureEnumerateA
-
-
-typedef struct {
- // DirectSound Playback Device
- IDirectSound *DS;
- IDirectSoundBuffer *PrimaryBuffer;
- IDirectSoundBuffer *Buffer;
- IDirectSoundNotify *Notifies;
- HANDLE NotifyEvent;
-
- volatile int killNow;
- althread_t thread;
-} DSoundPlaybackData;
-
-typedef struct {
- // DirectSound Capture Device
- IDirectSoundCapture *DSC;
- IDirectSoundCaptureBuffer *DSCbuffer;
- DWORD BufferBytes;
- DWORD Cursor;
- RingBuffer *Ring;
-} DSoundCaptureData;
-
-
-typedef struct {
- ALCchar *name;
- GUID guid;
-} DevMap;
-
-static DevMap *PlaybackDeviceList;
-static ALuint NumPlaybackDevices;
-static DevMap *CaptureDeviceList;
-static ALuint NumCaptureDevices;
+#define DirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW
+#endif
-#define MAX_UPDATES 128
static ALCboolean DSoundLoad(void)
{
+#ifdef HAVE_DYNLOAD
if(!ds_handle)
{
ds_handle = LoadLib("dsound.dll");
@@ -121,117 +93,133 @@ static ALCboolean DSoundLoad(void)
} \
} while(0)
LOAD_FUNC(DirectSoundCreate);
- LOAD_FUNC(DirectSoundEnumerateA);
+ LOAD_FUNC(DirectSoundEnumerateW);
LOAD_FUNC(DirectSoundCaptureCreate);
- LOAD_FUNC(DirectSoundCaptureEnumerateA);
+ LOAD_FUNC(DirectSoundCaptureEnumerateW);
#undef LOAD_FUNC
}
+#endif
return ALC_TRUE;
}
-static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR UNUSED(drvname), LPVOID UNUSED(data))
+#define MAX_UPDATES 128
+
+typedef struct {
+ al_string name;
+ GUID guid;
+} DevMap;
+DECL_VECTOR(DevMap)
+
+vector_DevMap PlaybackDevices;
+vector_DevMap CaptureDevices;
+
+static void clear_devlist(vector_DevMap *list)
{
- LPOLESTR guidstr = NULL;
- char str[1024];
+ DevMap *iter, *end;
+
+ iter = VECTOR_ITER_BEGIN(*list);
+ end = VECTOR_ITER_END(*list);
+ for(;iter != end;++iter)
+ AL_STRING_DEINIT(iter->name);
+ VECTOR_RESIZE(*list, 0);
+}
+
+static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data)
+{
+ vector_DevMap *devices = data;
+ OLECHAR *guidstr = NULL;
+ DevMap *iter, *end;
+ DevMap entry;
HRESULT hr;
- void *temp;
int count;
- ALuint i;
if(!guid)
return TRUE;
+ AL_STRING_INIT(entry.name);
+
count = 0;
do {
- if(count == 0)
- snprintf(str, sizeof(str), "%s", desc);
- else
- snprintf(str, sizeof(str), "%s #%d", desc, count+1);
+ al_string_copy_wcstr(&entry.name, desc);
+ if(count != 0)
+ {
+ char str[64];
+ snprintf(str, sizeof(str), " #%d", count+1);
+ al_string_append_cstr(&entry.name, str);
+ }
count++;
- for(i = 0;i < NumPlaybackDevices;i++)
+ iter = VECTOR_ITER_BEGIN(*devices);
+ end = VECTOR_ITER_END(*devices);
+ for(;iter != end;++iter)
{
- if(strcmp(str, PlaybackDeviceList[i].name) == 0)
+ if(al_string_cmp(entry.name, iter->name) == 0)
break;
}
- } while(i != NumPlaybackDevices);
+ } while(iter != end);
+ entry.guid = *guid;
hr = StringFromCLSID(guid, &guidstr);
if(SUCCEEDED(hr))
{
- TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
+ TRACE("Got device \"%s\", GUID \"%ls\"\n", al_string_get_cstr(entry.name), guidstr);
CoTaskMemFree(guidstr);
}
- temp = realloc(PlaybackDeviceList, sizeof(DevMap) * (NumPlaybackDevices+1));
- if(temp)
- {
- PlaybackDeviceList = temp;
- PlaybackDeviceList[NumPlaybackDevices].name = strdup(str);
- PlaybackDeviceList[NumPlaybackDevices].guid = *guid;
- NumPlaybackDevices++;
- }
+ VECTOR_PUSH_BACK(*devices, entry);
return TRUE;
}
-static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR UNUSED(drvname), LPVOID UNUSED(data))
-{
- LPOLESTR guidstr = NULL;
- char str[1024];
- HRESULT hr;
- void *temp;
- int count;
- ALuint i;
+typedef struct ALCdsoundPlayback {
+ DERIVE_FROM_TYPE(ALCbackend);
- if(!guid)
- return TRUE;
+ IDirectSound *DS;
+ IDirectSoundBuffer *PrimaryBuffer;
+ IDirectSoundBuffer *Buffer;
+ IDirectSoundNotify *Notifies;
+ HANDLE NotifyEvent;
- count = 0;
- do {
- if(count == 0)
- snprintf(str, sizeof(str), "%s", desc);
- else
- snprintf(str, sizeof(str), "%s #%d", desc, count+1);
- count++;
+ volatile int killNow;
+ althrd_t thread;
+} ALCdsoundPlayback;
- for(i = 0;i < NumCaptureDevices;i++)
- {
- if(strcmp(str, CaptureDeviceList[i].name) == 0)
- break;
- }
- } while(i != NumCaptureDevices);
+static int ALCdsoundPlayback_mixerProc(void *ptr);
- hr = StringFromCLSID(guid, &guidstr);
- if(SUCCEEDED(hr))
- {
- TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
- CoTaskMemFree(guidstr);
- }
+static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, Destruct)
+static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name);
+static void ALCdsoundPlayback_close(ALCdsoundPlayback *self);
+static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self);
+static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self);
+static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self);
+static DECLARE_FORWARD2(ALCdsoundPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCdsoundPlayback)
- temp = realloc(CaptureDeviceList, sizeof(DevMap) * (NumCaptureDevices+1));
- if(temp)
- {
- CaptureDeviceList = temp;
- CaptureDeviceList[NumCaptureDevices].name = strdup(str);
- CaptureDeviceList[NumCaptureDevices].guid = *guid;
- NumCaptureDevices++;
- }
+DEFINE_ALCBACKEND_VTABLE(ALCdsoundPlayback);
- return TRUE;
+
+static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self);
}
-FORCE_ALIGN static ALuint DSoundPlaybackProc(ALvoid *ptr)
+FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
{
- ALCdevice *Device = (ALCdevice*)ptr;
- DSoundPlaybackData *data = (DSoundPlaybackData*)Device->ExtraData;
+ ALCdsoundPlayback *self = ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
DSBCAPS DSBCaps;
DWORD LastCursor = 0;
DWORD PlayCursor;
- VOID *WritePtr1, *WritePtr2;
+ void *WritePtr1, *WritePtr2;
DWORD WriteCnt1, WriteCnt2;
BOOL Playing = FALSE;
DWORD FrameSize;
@@ -240,47 +228,47 @@ FORCE_ALIGN static ALuint DSoundPlaybackProc(ALvoid *ptr)
HRESULT err;
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
memset(&DSBCaps, 0, sizeof(DSBCaps));
DSBCaps.dwSize = sizeof(DSBCaps);
- err = IDirectSoundBuffer_GetCaps(data->Buffer, &DSBCaps);
+ err = IDirectSoundBuffer_GetCaps(self->Buffer, &DSBCaps);
if(FAILED(err))
{
ERR("Failed to get buffer caps: 0x%lx\n", err);
- ALCdevice_Lock(Device);
- aluHandleDisconnect(Device);
- ALCdevice_Unlock(Device);
+ ALCdevice_Lock(device);
+ aluHandleDisconnect(device);
+ ALCdevice_Unlock(device);
return 1;
}
- FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
- FragSize = Device->UpdateSize * FrameSize;
+ FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ FragSize = device->UpdateSize * FrameSize;
- IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &LastCursor, NULL);
- while(!data->killNow)
+ IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &LastCursor, NULL);
+ while(!self->killNow)
{
// Get current play cursor
- IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &PlayCursor, NULL);
+ IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &PlayCursor, NULL);
avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
if(avail < FragSize)
{
if(!Playing)
{
- err = IDirectSoundBuffer_Play(data->Buffer, 0, 0, DSBPLAY_LOOPING);
+ err = IDirectSoundBuffer_Play(self->Buffer, 0, 0, DSBPLAY_LOOPING);
if(FAILED(err))
{
ERR("Failed to play buffer: 0x%lx\n", err);
- ALCdevice_Lock(Device);
- aluHandleDisconnect(Device);
- ALCdevice_Unlock(Device);
+ ALCdevice_Lock(device);
+ aluHandleDisconnect(device);
+ ALCdevice_Unlock(device);
return 1;
}
Playing = TRUE;
}
- avail = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE);
+ avail = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE);
if(avail != WAIT_OBJECT_0)
ERR("WaitForSingleObjectEx error: 0x%lx\n", avail);
continue;
@@ -290,18 +278,18 @@ FORCE_ALIGN static ALuint DSoundPlaybackProc(ALvoid *ptr)
// Lock output buffer
WriteCnt1 = 0;
WriteCnt2 = 0;
- err = IDirectSoundBuffer_Lock(data->Buffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
+ err = IDirectSoundBuffer_Lock(self->Buffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
// If the buffer is lost, restore it and lock
if(err == DSERR_BUFFERLOST)
{
WARN("Buffer lost, restoring...\n");
- err = IDirectSoundBuffer_Restore(data->Buffer);
+ err = IDirectSoundBuffer_Restore(self->Buffer);
if(SUCCEEDED(err))
{
Playing = FALSE;
LastCursor = 0;
- err = IDirectSoundBuffer_Lock(data->Buffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
+ err = IDirectSoundBuffer_Lock(self->Buffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
}
}
@@ -309,18 +297,18 @@ FORCE_ALIGN static ALuint DSoundPlaybackProc(ALvoid *ptr)
if(SUCCEEDED(err))
{
// If we have an active context, mix data directly into output buffer otherwise fill with silence
- aluMixData(Device, WritePtr1, WriteCnt1/FrameSize);
- aluMixData(Device, WritePtr2, WriteCnt2/FrameSize);
+ aluMixData(device, WritePtr1, WriteCnt1/FrameSize);
+ aluMixData(device, WritePtr2, WriteCnt2/FrameSize);
// Unlock output buffer only when successfully locked
- IDirectSoundBuffer_Unlock(data->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
+ IDirectSoundBuffer_Unlock(self->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
}
else
{
ERR("Buffer lock error: %#lx\n", err);
- ALCdevice_Lock(Device);
- aluHandleDisconnect(Device);
- ALCdevice_Unlock(Device);
+ ALCdevice_Lock(device);
+ aluHandleDisconnect(device);
+ ALCdevice_Unlock(device);
return 1;
}
@@ -332,94 +320,95 @@ FORCE_ALIGN static ALuint DSoundPlaybackProc(ALvoid *ptr)
return 0;
}
-static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
+static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName)
{
- DSoundPlaybackData *data = NULL;
- LPGUID guid = NULL;
- HRESULT hr;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ GUID *guid = NULL;
+ HRESULT hr, hrcom;
- if(!PlaybackDeviceList)
+ if(VECTOR_SIZE(PlaybackDevices) == 0)
{
- hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
+ /* Initialize COM to prevent name truncation */
+ hrcom = CoInitialize(NULL);
+ hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices);
if(FAILED(hr))
- ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
+ ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr);
+ if(SUCCEEDED(hrcom))
+ CoUninitialize();
}
- if(!deviceName && NumPlaybackDevices > 0)
+ if(!deviceName && VECTOR_SIZE(PlaybackDevices) > 0)
{
- deviceName = PlaybackDeviceList[0].name;
- guid = &PlaybackDeviceList[0].guid;
+ deviceName = al_string_get_cstr(VECTOR_FRONT(PlaybackDevices).name);
+ guid = &VECTOR_FRONT(PlaybackDevices).guid;
}
else
{
- ALuint i;
+ DevMap *iter, *end;
- for(i = 0;i < NumPlaybackDevices;i++)
+ iter = VECTOR_ITER_BEGIN(PlaybackDevices);
+ end = VECTOR_ITER_END(PlaybackDevices);
+ for(;iter != end;++iter)
{
- if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
+ if(al_string_cmp_cstr(iter->name, deviceName) == 0)
{
- guid = &PlaybackDeviceList[i].guid;
+ guid = &iter->guid;
break;
}
}
- if(i == NumPlaybackDevices)
+ if(iter == end)
return ALC_INVALID_VALUE;
}
- //Initialise requested device
- data = calloc(1, sizeof(DSoundPlaybackData));
- if(!data)
- return ALC_OUT_OF_MEMORY;
-
hr = DS_OK;
- data->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if(data->NotifyEvent == NULL)
+ self->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if(self->NotifyEvent == NULL)
hr = E_FAIL;
//DirectSound Init code
if(SUCCEEDED(hr))
- hr = DirectSoundCreate(guid, &data->DS, NULL);
+ hr = DirectSoundCreate(guid, &self->DS, NULL);
if(SUCCEEDED(hr))
- hr = IDirectSound_SetCooperativeLevel(data->DS, GetForegroundWindow(), DSSCL_PRIORITY);
+ hr = IDirectSound_SetCooperativeLevel(self->DS, GetForegroundWindow(), DSSCL_PRIORITY);
if(FAILED(hr))
{
- if(data->DS)
- IDirectSound_Release(data->DS);
- if(data->NotifyEvent)
- CloseHandle(data->NotifyEvent);
- free(data);
+ if(self->DS)
+ IDirectSound_Release(self->DS);
+ self->DS = NULL;
+ if(self->NotifyEvent)
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
+
ERR("Device init failed: 0x%08lx\n", hr);
return ALC_INVALID_VALUE;
}
- device->DeviceName = strdup(deviceName);
- device->ExtraData = data;
+ al_string_copy_cstr(&device->DeviceName, deviceName);
+
return ALC_NO_ERROR;
}
-static void DSoundClosePlayback(ALCdevice *device)
+static void ALCdsoundPlayback_close(ALCdsoundPlayback *self)
{
- DSoundPlaybackData *data = device->ExtraData;
-
- if(data->Notifies)
- IDirectSoundNotify_Release(data->Notifies);
- data->Notifies = NULL;
- if(data->Buffer)
- IDirectSoundBuffer_Release(data->Buffer);
- data->Buffer = NULL;
- if(data->PrimaryBuffer != NULL)
- IDirectSoundBuffer_Release(data->PrimaryBuffer);
- data->PrimaryBuffer = NULL;
-
- IDirectSound_Release(data->DS);
- CloseHandle(data->NotifyEvent);
- free(data);
- device->ExtraData = NULL;
+ if(self->Notifies)
+ IDirectSoundNotify_Release(self->Notifies);
+ self->Notifies = NULL;
+ if(self->Buffer)
+ IDirectSoundBuffer_Release(self->Buffer);
+ self->Buffer = NULL;
+ if(self->PrimaryBuffer != NULL)
+ IDirectSoundBuffer_Release(self->PrimaryBuffer);
+ self->PrimaryBuffer = NULL;
+
+ IDirectSound_Release(self->DS);
+ self->DS = NULL;
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
}
-static ALCboolean DSoundResetPlayback(ALCdevice *device)
+static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
{
- DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
DSBUFFERDESC DSBDescription;
WAVEFORMATEXTENSIBLE OutputType;
DWORD speakers;
@@ -427,15 +416,15 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device)
memset(&OutputType, 0, sizeof(OutputType));
- if(data->Notifies)
- IDirectSoundNotify_Release(data->Notifies);
- data->Notifies = NULL;
- if(data->Buffer)
- IDirectSoundBuffer_Release(data->Buffer);
- data->Buffer = NULL;
- if(data->PrimaryBuffer != NULL)
- IDirectSoundBuffer_Release(data->PrimaryBuffer);
- data->PrimaryBuffer = NULL;
+ if(self->Notifies)
+ IDirectSoundNotify_Release(self->Notifies);
+ self->Notifies = NULL;
+ if(self->Buffer)
+ IDirectSoundBuffer_Release(self->Buffer);
+ self->Buffer = NULL;
+ if(self->PrimaryBuffer != NULL)
+ IDirectSoundBuffer_Release(self->PrimaryBuffer);
+ self->PrimaryBuffer = NULL;
switch(device->FmtType)
{
@@ -458,7 +447,7 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device)
break;
}
- hr = IDirectSound_GetSpeakerConfig(data->DS, &speakers);
+ hr = IDirectSound_GetSpeakerConfig(self->DS, &speakers);
if(SUCCEEDED(hr))
{
if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
@@ -551,21 +540,21 @@ retry_open:
else
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- if(data->PrimaryBuffer)
- IDirectSoundBuffer_Release(data->PrimaryBuffer);
- data->PrimaryBuffer = NULL;
+ if(self->PrimaryBuffer)
+ IDirectSoundBuffer_Release(self->PrimaryBuffer);
+ self->PrimaryBuffer = NULL;
}
else
{
- if(SUCCEEDED(hr) && !data->PrimaryBuffer)
+ if(SUCCEEDED(hr) && !self->PrimaryBuffer)
{
memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
DSBDescription.dwSize=sizeof(DSBUFFERDESC);
DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
- hr = IDirectSound_CreateSoundBuffer(data->DS, &DSBDescription, &data->PrimaryBuffer, NULL);
+ hr = IDirectSound_CreateSoundBuffer(self->DS, &DSBDescription, &self->PrimaryBuffer, NULL);
}
if(SUCCEEDED(hr))
- hr = IDirectSoundBuffer_SetFormat(data->PrimaryBuffer,&OutputType.Format);
+ hr = IDirectSoundBuffer_SetFormat(self->PrimaryBuffer,&OutputType.Format);
}
if(SUCCEEDED(hr))
@@ -583,7 +572,7 @@ retry_open:
DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates *
OutputType.Format.nBlockAlign;
DSBDescription.lpwfxFormat=&OutputType.Format;
- hr = IDirectSound_CreateSoundBuffer(data->DS, &DSBDescription, &data->Buffer, NULL);
+ hr = IDirectSound_CreateSoundBuffer(self->DS, &DSBDescription, &self->Buffer, NULL);
if(FAILED(hr) && device->FmtType == DevFmtFloat)
{
device->FmtType = DevFmtShort;
@@ -593,7 +582,7 @@ retry_open:
if(SUCCEEDED(hr))
{
- hr = IDirectSoundBuffer_QueryInterface(data->Buffer, &IID_IDirectSoundNotify, (LPVOID *)&data->Notifies);
+ hr = IDirectSoundBuffer_QueryInterface(self->Buffer, &IID_IDirectSoundNotify, (void**)&self->Notifies);
if(SUCCEEDED(hr))
{
DSBPOSITIONNOTIFY notifies[MAX_UPDATES];
@@ -603,97 +592,130 @@ retry_open:
{
notifies[i].dwOffset = i * device->UpdateSize *
OutputType.Format.nBlockAlign;
- notifies[i].hEventNotify = data->NotifyEvent;
+ notifies[i].hEventNotify = self->NotifyEvent;
}
- if(IDirectSoundNotify_SetNotificationPositions(data->Notifies, device->NumUpdates, notifies) != DS_OK)
+ if(IDirectSoundNotify_SetNotificationPositions(self->Notifies, device->NumUpdates, notifies) != DS_OK)
hr = E_FAIL;
}
}
if(FAILED(hr))
{
- if(data->Notifies != NULL)
- IDirectSoundNotify_Release(data->Notifies);
- data->Notifies = NULL;
- if(data->Buffer != NULL)
- IDirectSoundBuffer_Release(data->Buffer);
- data->Buffer = NULL;
- if(data->PrimaryBuffer != NULL)
- IDirectSoundBuffer_Release(data->PrimaryBuffer);
- data->PrimaryBuffer = NULL;
+ if(self->Notifies != NULL)
+ IDirectSoundNotify_Release(self->Notifies);
+ self->Notifies = NULL;
+ if(self->Buffer != NULL)
+ IDirectSoundBuffer_Release(self->Buffer);
+ self->Buffer = NULL;
+ if(self->PrimaryBuffer != NULL)
+ IDirectSoundBuffer_Release(self->PrimaryBuffer);
+ self->PrimaryBuffer = NULL;
return ALC_FALSE;
}
- ResetEvent(data->NotifyEvent);
+ ResetEvent(self->NotifyEvent);
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
-static ALCboolean DSoundStartPlayback(ALCdevice *device)
+static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self)
{
- DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData;
-
- if(!StartThread(&data->thread, DSoundPlaybackProc, device))
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCdsoundPlayback_mixerProc, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
}
-static void DSoundStopPlayback(ALCdevice *device)
+static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self)
{
- DSoundPlaybackData *data = device->ExtraData;
+ int res;
- if(!data->thread)
+ if(self->killNow)
return;
- data->killNow = 1;
- StopThread(data->thread);
- data->thread = NULL;
+ self->killNow = 1;
+ althrd_join(self->thread, &res);
- data->killNow = 0;
- IDirectSoundBuffer_Stop(data->Buffer);
+ IDirectSoundBuffer_Stop(self->Buffer);
}
-static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
+
+typedef struct ALCdsoundCapture {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ IDirectSoundCapture *DSC;
+ IDirectSoundCaptureBuffer *DSCbuffer;
+ DWORD BufferBytes;
+ DWORD Cursor;
+ RingBuffer *Ring;
+} ALCdsoundCapture;
+
+static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, Destruct)
+static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name);
+static void ALCdsoundCapture_close(ALCdsoundCapture *self);
+static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALCboolean, reset)
+static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self);
+static void ALCdsoundCapture_stop(ALCdsoundCapture *self);
+static ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples);
+static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self);
+static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCdsoundCapture)
+
+DEFINE_ALCBACKEND_VTABLE(ALCdsoundCapture);
+
+static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCdsoundCapture, ALCbackend, self);
+}
+
+
+static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName)
{
- DSoundCaptureData *data = NULL;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
WAVEFORMATEXTENSIBLE InputType;
DSCBUFFERDESC DSCBDescription;
- LPGUID guid = NULL;
+ GUID *guid = NULL;
HRESULT hr, hrcom;
ALuint samples;
- if(!CaptureDeviceList)
+ if(VECTOR_SIZE(CaptureDevices) == 0)
{
/* Initialize COM to prevent name truncation */
hrcom = CoInitialize(NULL);
- hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
+ hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices);
if(FAILED(hr))
- ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
+ ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr);
if(SUCCEEDED(hrcom))
CoUninitialize();
}
- if(!deviceName && NumCaptureDevices > 0)
+ if(!deviceName && VECTOR_SIZE(CaptureDevices) > 0)
{
- deviceName = CaptureDeviceList[0].name;
- guid = &CaptureDeviceList[0].guid;
+ deviceName = al_string_get_cstr(VECTOR_FRONT(CaptureDevices).name);
+ guid = &VECTOR_FRONT(CaptureDevices).guid;
}
else
{
- ALuint i;
+ DevMap *iter, *end;
- for(i = 0;i < NumCaptureDevices;i++)
+ iter = VECTOR_ITER_BEGIN(CaptureDevices);
+ end = VECTOR_ITER_END(CaptureDevices);
+ for(;iter != end;++iter)
{
- if(strcmp(deviceName, CaptureDeviceList[i].name) == 0)
+ if(al_string_cmp_cstr(iter->name, deviceName) == 0)
{
- guid = &CaptureDeviceList[i].guid;
+ guid = &iter->guid;
break;
}
}
- if(i == NumCaptureDevices)
+ if(iter == end)
return ALC_INVALID_VALUE;
}
@@ -712,16 +734,8 @@ static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
break;
}
- //Initialise requested device
- data = calloc(1, sizeof(DSoundCaptureData));
- if(!data)
- return ALC_OUT_OF_MEMORY;
-
- hr = DS_OK;
-
//DirectSoundCapture Init code
- if(SUCCEEDED(hr))
- hr = DirectSoundCaptureCreate(guid, &data->DSC, NULL);
+ hr = DirectSoundCaptureCreate(guid, &self->DSC, NULL);
if(SUCCEEDED(hr))
{
memset(&InputType, 0, sizeof(InputType));
@@ -806,12 +820,12 @@ static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
DSCBDescription.lpwfxFormat = &InputType.Format;
- hr = IDirectSoundCapture_CreateCaptureBuffer(data->DSC, &DSCBDescription, &data->DSCbuffer, NULL);
+ hr = IDirectSoundCapture_CreateCaptureBuffer(self->DSC, &DSCBDescription, &self->DSCbuffer, NULL);
}
if(SUCCEEDED(hr))
{
- data->Ring = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates);
- if(data->Ring == NULL)
+ self->Ring = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates);
+ if(self->Ring == NULL)
hr = DSERR_OUTOFMEMORY;
}
@@ -819,218 +833,237 @@ static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
{
ERR("Device init failed: 0x%08lx\n", hr);
- DestroyRingBuffer(data->Ring);
- data->Ring = NULL;
- if(data->DSCbuffer != NULL)
- IDirectSoundCaptureBuffer_Release(data->DSCbuffer);
- data->DSCbuffer = NULL;
- if(data->DSC)
- IDirectSoundCapture_Release(data->DSC);
- data->DSC = NULL;
+ DestroyRingBuffer(self->Ring);
+ self->Ring = NULL;
+ if(self->DSCbuffer != NULL)
+ IDirectSoundCaptureBuffer_Release(self->DSCbuffer);
+ self->DSCbuffer = NULL;
+ if(self->DSC)
+ IDirectSoundCapture_Release(self->DSC);
+ self->DSC = NULL;
- free(data);
return ALC_INVALID_VALUE;
}
- data->BufferBytes = DSCBDescription.dwBufferBytes;
+ self->BufferBytes = DSCBDescription.dwBufferBytes;
SetDefaultWFXChannelOrder(device);
- device->DeviceName = strdup(deviceName);
- device->ExtraData = data;
+ al_string_copy_cstr(&device->DeviceName, deviceName);
return ALC_NO_ERROR;
}
-static void DSoundCloseCapture(ALCdevice *device)
+static void ALCdsoundCapture_close(ALCdsoundCapture *self)
{
- DSoundCaptureData *data = device->ExtraData;
+ DestroyRingBuffer(self->Ring);
+ self->Ring = NULL;
- DestroyRingBuffer(data->Ring);
- data->Ring = NULL;
-
- if(data->DSCbuffer != NULL)
+ if(self->DSCbuffer != NULL)
{
- IDirectSoundCaptureBuffer_Stop(data->DSCbuffer);
- IDirectSoundCaptureBuffer_Release(data->DSCbuffer);
- data->DSCbuffer = NULL;
+ IDirectSoundCaptureBuffer_Stop(self->DSCbuffer);
+ IDirectSoundCaptureBuffer_Release(self->DSCbuffer);
+ self->DSCbuffer = NULL;
}
- IDirectSoundCapture_Release(data->DSC);
- data->DSC = NULL;
-
- free(data);
- device->ExtraData = NULL;
+ IDirectSoundCapture_Release(self->DSC);
+ self->DSC = NULL;
}
-static void DSoundStartCapture(ALCdevice *device)
+static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self)
{
- DSoundCaptureData *data = device->ExtraData;
HRESULT hr;
- hr = IDirectSoundCaptureBuffer_Start(data->DSCbuffer, DSCBSTART_LOOPING);
+ hr = IDirectSoundCaptureBuffer_Start(self->DSCbuffer, DSCBSTART_LOOPING);
if(FAILED(hr))
{
ERR("start failed: 0x%08lx\n", hr);
- aluHandleDisconnect(device);
+ aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
+ return ALC_FALSE;
}
+
+ return ALC_TRUE;
}
-static void DSoundStopCapture(ALCdevice *device)
+static void ALCdsoundCapture_stop(ALCdsoundCapture *self)
{
- DSoundCaptureData *data = device->ExtraData;
HRESULT hr;
- hr = IDirectSoundCaptureBuffer_Stop(data->DSCbuffer);
+ hr = IDirectSoundCaptureBuffer_Stop(self->DSCbuffer);
if(FAILED(hr))
{
ERR("stop failed: 0x%08lx\n", hr);
- aluHandleDisconnect(device);
+ aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
}
}
-static ALCenum DSoundCaptureSamples(ALCdevice *Device, ALCvoid *pBuffer, ALCuint lSamples)
+static ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples)
{
- DSoundCaptureData *data = Device->ExtraData;
- ReadRingBuffer(data->Ring, pBuffer, lSamples);
+ ReadRingBuffer(self->Ring, buffer, samples);
return ALC_NO_ERROR;
}
-static ALCuint DSoundAvailableSamples(ALCdevice *Device)
+static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self)
{
- DSoundCaptureData *data = Device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
DWORD ReadCursor, LastCursor, BufferBytes, NumBytes;
- VOID *ReadPtr1, *ReadPtr2;
+ void *ReadPtr1, *ReadPtr2;
DWORD ReadCnt1, ReadCnt2;
DWORD FrameSize;
HRESULT hr;
- if(!Device->Connected)
+ if(!device->Connected)
goto done;
- FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
- BufferBytes = data->BufferBytes;
- LastCursor = data->Cursor;
+ FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ BufferBytes = self->BufferBytes;
+ LastCursor = self->Cursor;
- hr = IDirectSoundCaptureBuffer_GetCurrentPosition(data->DSCbuffer, NULL, &ReadCursor);
+ hr = IDirectSoundCaptureBuffer_GetCurrentPosition(self->DSCbuffer, NULL, &ReadCursor);
if(SUCCEEDED(hr))
{
NumBytes = (ReadCursor-LastCursor + BufferBytes) % BufferBytes;
if(NumBytes == 0)
goto done;
- hr = IDirectSoundCaptureBuffer_Lock(data->DSCbuffer, LastCursor, NumBytes,
+ hr = IDirectSoundCaptureBuffer_Lock(self->DSCbuffer, LastCursor, NumBytes,
&ReadPtr1, &ReadCnt1,
&ReadPtr2, &ReadCnt2, 0);
}
if(SUCCEEDED(hr))
{
- WriteRingBuffer(data->Ring, ReadPtr1, ReadCnt1/FrameSize);
+ WriteRingBuffer(self->Ring, ReadPtr1, ReadCnt1/FrameSize);
if(ReadPtr2 != NULL)
- WriteRingBuffer(data->Ring, ReadPtr2, ReadCnt2/FrameSize);
- hr = IDirectSoundCaptureBuffer_Unlock(data->DSCbuffer,
+ WriteRingBuffer(self->Ring, ReadPtr2, ReadCnt2/FrameSize);
+ hr = IDirectSoundCaptureBuffer_Unlock(self->DSCbuffer,
ReadPtr1, ReadCnt1,
ReadPtr2, ReadCnt2);
- data->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes;
+ self->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes;
}
if(FAILED(hr))
{
ERR("update failed: 0x%08lx\n", hr);
- aluHandleDisconnect(Device);
+ aluHandleDisconnect(device);
}
done:
- return RingBufferSize(data->Ring);
+ return RingBufferSize(self->Ring);
}
-static const BackendFuncs DSoundFuncs = {
- DSoundOpenPlayback,
- DSoundClosePlayback,
- DSoundResetPlayback,
- DSoundStartPlayback,
- DSoundStopPlayback,
- DSoundOpenCapture,
- DSoundCloseCapture,
- DSoundStartCapture,
- DSoundStopCapture,
- DSoundCaptureSamples,
- DSoundAvailableSamples,
- ALCdevice_GetLatencyDefault
-};
+static inline void AppendAllDevicesList2(const DevMap *entry)
+{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
+static inline void AppendCaptureDeviceList2(const DevMap *entry)
+{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
+typedef struct ALCdsoundBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCdsoundBackendFactory;
+#define ALCDSOUNDBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCdsoundBackendFactory, ALCbackendFactory) } }
-ALCboolean alcDSoundInit(BackendFuncs *FuncList)
+ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
+
+static ALCboolean ALCdsoundBackendFactory_init(ALCdsoundBackendFactory *self);
+static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory *self);
+static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory *self, ALCbackend_Type type);
+static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory);
+
+
+ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void)
{
+ static ALCdsoundBackendFactory factory = ALCDSOUNDBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
+}
+
+
+static ALCboolean ALCdsoundBackendFactory_init(ALCdsoundBackendFactory* UNUSED(self))
+{
+ VECTOR_INIT(PlaybackDevices);
+ VECTOR_INIT(CaptureDevices);
+
if(!DSoundLoad())
return ALC_FALSE;
- *FuncList = DSoundFuncs;
return ALC_TRUE;
}
-void alcDSoundDeinit(void)
+static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory* UNUSED(self))
{
- ALuint i;
-
- for(i = 0;i < NumPlaybackDevices;++i)
- free(PlaybackDeviceList[i].name);
- free(PlaybackDeviceList);
- PlaybackDeviceList = NULL;
- NumPlaybackDevices = 0;
+ clear_devlist(&PlaybackDevices);
+ VECTOR_DEINIT(PlaybackDevices);
- for(i = 0;i < NumCaptureDevices;++i)
- free(CaptureDeviceList[i].name);
- free(CaptureDeviceList);
- CaptureDeviceList = NULL;
- NumCaptureDevices = 0;
+ clear_devlist(&CaptureDevices);
+ VECTOR_DEINIT(CaptureDevices);
+#ifdef HAVE_DYNLOAD
if(ds_handle)
CloseLib(ds_handle);
ds_handle = NULL;
+#endif
}
-void alcDSoundProbe(enum DevProbe type)
+static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+ return ALC_TRUE;
+ return ALC_FALSE;
+}
+
+static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type)
{
HRESULT hr, hrcom;
- ALuint i;
+ /* Initialize COM to prevent name truncation */
+ hrcom = CoInitialize(NULL);
switch(type)
{
case ALL_DEVICE_PROBE:
- for(i = 0;i < NumPlaybackDevices;++i)
- free(PlaybackDeviceList[i].name);
- free(PlaybackDeviceList);
- PlaybackDeviceList = NULL;
- NumPlaybackDevices = 0;
-
- hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
+ clear_devlist(&PlaybackDevices);
+ hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices);
if(FAILED(hr))
- ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr);
- else
- {
- for(i = 0;i < NumPlaybackDevices;i++)
- AppendAllDevicesList(PlaybackDeviceList[i].name);
- }
+ ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr);
+ VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
- for(i = 0;i < NumCaptureDevices;++i)
- free(CaptureDeviceList[i].name);
- free(CaptureDeviceList);
- CaptureDeviceList = NULL;
- NumCaptureDevices = 0;
-
- /* Initialize COM to prevent name truncation */
- hrcom = CoInitialize(NULL);
- hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
+ clear_devlist(&CaptureDevices);
+ hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices);
if(FAILED(hr))
- ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr);
- else
- {
- for(i = 0;i < NumCaptureDevices;i++)
- AppendCaptureDeviceList(CaptureDeviceList[i].name);
- }
- if(SUCCEEDED(hrcom))
- CoUninitialize();
+ ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr);
+ VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
break;
}
+ if(SUCCEEDED(hrcom))
+ CoUninitialize();
+}
+
+static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCdsoundPlayback *backend;
+
+ backend = ALCdsoundPlayback_New(sizeof(*backend));
+ if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
+
+ ALCdsoundPlayback_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ if(type == ALCbackend_Capture)
+ {
+ ALCdsoundCapture *backend;
+
+ backend = ALCdsoundCapture_New(sizeof(*backend));
+ if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
+
+ ALCdsoundCapture_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
}
diff --git a/Alc/backends/loopback.c b/Alc/backends/loopback.c
index cd5b1a1e..505dfacf 100644
--- a/Alc/backends/loopback.c
+++ b/Alc/backends/loopback.c
@@ -44,7 +44,7 @@ static DECLARE_FORWARD(ALCloopback, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCloopback, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock)
-static void ALCloopback_Delete(ALCloopback *self);
+DECLARE_DEFAULT_ALLOCATORS(ALCloopback)
DEFINE_ALCBACKEND_VTABLE(ALCloopback);
@@ -59,7 +59,7 @@ static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- device->DeviceName = strdup(name);
+ al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
@@ -83,12 +83,6 @@ static void ALCloopback_stop(ALCloopback* UNUSED(self))
}
-static void ALCloopback_Delete(ALCloopback *self)
-{
- free(self);
-}
-
-
typedef struct ALCloopbackFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCloopbackFactory;
@@ -127,14 +121,18 @@ static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevP
static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
- ALCloopback *backend;
+ if(type == ALCbackend_Loopback)
+ {
+ ALCloopback *backend;
- assert(type == ALCbackend_Loopback);
+ backend = ALCloopback_New(sizeof(*backend));
+ if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
- backend = calloc(1, sizeof(*backend));
- if(!backend) return NULL;
+ ALCloopback_Construct(backend, device);
- ALCloopback_Construct(backend, device);
+ return STATIC_CAST(ALCbackend, backend);
+ }
- return STATIC_CAST(ALCbackend, backend);
+ return NULL;
}
diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c
index b93ff667..d732c3e1 100644
--- a/Alc/backends/mmdevapi.c
+++ b/Alc/backends/mmdevapi.c
@@ -42,6 +42,9 @@
#include "alu.h"
#include "threads.h"
#include "compat.h"
+#include "alstring.h"
+
+#include "backends/base.h"
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
@@ -59,31 +62,27 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
typedef struct {
+ al_string name;
WCHAR *devid;
+} DevMap;
+DECL_VECTOR(DevMap)
- IMMDevice *mmdev;
- IAudioClient *client;
- IAudioRenderClient *render;
- HANDLE NotifyEvent;
-
- HANDLE MsgEvent;
-
- volatile UINT32 Padding;
-
- volatile int killNow;
- althread_t thread;
-} MMDevApiData;
-
+static void clear_devlist(vector_DevMap *list)
+{
+ DevMap *iter, *end;
-typedef struct {
- ALCchar *name;
- WCHAR *devid;
-} DevMap;
+ iter = VECTOR_ITER_BEGIN(*list);
+ end = VECTOR_ITER_END(*list);
+ for(;iter != end;iter++)
+ {
+ AL_STRING_DEINIT(iter->name);
+ free(iter->devid);
+ }
+ VECTOR_RESIZE(*list, 0);
+}
-static DevMap *PlaybackDeviceList;
-static ALuint NumPlaybackDevices;
-static DevMap *CaptureDeviceList;
-static ALuint NumCaptureDevices;
+static vector_DevMap PlaybackDevices;
+static vector_DevMap CaptureDevices;
static HANDLE ThreadHdl;
@@ -103,6 +102,12 @@ typedef struct {
#define WM_USER_Enumerate (WM_USER+5)
#define WM_USER_Last (WM_USER+5)
+static inline void ReturnMsgResponse(ThreadRequest *req, HRESULT res)
+{
+ req->result = res;
+ SetEvent(req->FinishedEvt);
+}
+
static HRESULT WaitForResponse(ThreadRequest *req)
{
if(WaitForSingleObject(req->FinishedEvt, INFINITE) == WAIT_OBJECT_0)
@@ -112,45 +117,32 @@ static HRESULT WaitForResponse(ThreadRequest *req)
}
-static ALCchar *get_device_name(IMMDevice *device)
+static void get_device_name(IMMDevice *device, al_string *name)
{
- ALCchar *name = NULL;
IPropertyStore *ps;
PROPVARIANT pvname;
HRESULT hr;
- int len;
hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
if(FAILED(hr))
{
WARN("OpenPropertyStore failed: 0x%08lx\n", hr);
- return calloc(1, 1);
+ return;
}
PropVariantInit(&pvname);
hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname);
if(FAILED(hr))
- {
WARN("GetValue failed: 0x%08lx\n", hr);
- name = calloc(1, 1);
- }
else
- {
- if((len=WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, NULL, 0, NULL, NULL)) > 0)
- {
- name = calloc(1, len);
- WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, name, len, NULL, NULL);
- }
- }
+ al_string_copy_wcstr(name, pvname.pwszVal);
PropVariantClear(&pvname);
IPropertyStore_Release(ps);
-
- return name;
}
-static void add_device(IMMDevice *device, DevMap *devmap)
+static void add_device(IMMDevice *device, vector_DevMap *list)
{
LPWSTR devid;
HRESULT hr;
@@ -158,48 +150,52 @@ static void add_device(IMMDevice *device, DevMap *devmap)
hr = IMMDevice_GetId(device, &devid);
if(SUCCEEDED(hr))
{
- devmap->devid = strdupW(devid);
- devmap->name = get_device_name(device);
- TRACE("Got device \"%s\", \"%ls\"\n", devmap->name, devmap->devid);
+ DevMap entry;
+ AL_STRING_INIT(entry.name);
+
+ entry.devid = strdupW(devid);
+ get_device_name(device, &entry.name);
+
CoTaskMemFree(devid);
+
+ TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid);
+ VECTOR_PUSH_BACK(*list, entry);
}
}
-static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALuint *numdevs)
+static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list)
{
IMMDeviceCollection *coll;
IMMDevice *defdev = NULL;
- DevMap *devlist = NULL;
HRESULT hr;
UINT count;
- UINT idx;
UINT i;
hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flowdir, DEVICE_STATE_ACTIVE, &coll);
if(FAILED(hr))
{
ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr);
- return NULL;
+ return hr;
}
- idx = count = 0;
+ count = 0;
hr = IMMDeviceCollection_GetCount(coll, &count);
if(SUCCEEDED(hr) && count > 0)
{
- devlist = calloc(count, sizeof(*devlist));
- if(!devlist)
+ clear_devlist(list);
+ if(!VECTOR_RESERVE(*list, count+1))
{
IMMDeviceCollection_Release(coll);
- return NULL;
+ return E_OUTOFMEMORY;
}
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir,
eMultimedia, &defdev);
}
if(SUCCEEDED(hr) && defdev != NULL)
- add_device(defdev, &devlist[idx++]);
+ add_device(defdev, list);
- for(i = 0;i < count && idx < count;++i)
+ for(i = 0;i < count;++i)
{
IMMDevice *device;
@@ -207,7 +203,7 @@ static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALu
continue;
if(device != defdev)
- add_device(device, &devlist[idx++]);
+ add_device(device, list);
IMMDevice_Release(device);
}
@@ -215,15 +211,269 @@ static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALu
if(defdev) IMMDevice_Release(defdev);
IMMDeviceCollection_Release(coll);
- *numdevs = idx;
- return devlist;
+ return S_OK;
}
-FORCE_ALIGN static ALuint MMDevApiProc(ALvoid *ptr)
+/* Proxy interface used by the message handler. */
+struct ALCmmdevProxyVtable;
+
+typedef struct ALCmmdevProxy {
+ const struct ALCmmdevProxyVtable *vtbl;
+} ALCmmdevProxy;
+
+struct ALCmmdevProxyVtable {
+ HRESULT (*const openProxy)(ALCmmdevProxy*);
+ void (*const closeProxy)(ALCmmdevProxy*);
+
+ HRESULT (*const resetProxy)(ALCmmdevProxy*);
+ HRESULT (*const startProxy)(ALCmmdevProxy*);
+ void (*const stopProxy)(ALCmmdevProxy*);
+};
+
+#define DEFINE_ALCMMDEVPROXY_VTABLE(T) \
+DECLARE_THUNK(T, ALCmmdevProxy, HRESULT, openProxy) \
+DECLARE_THUNK(T, ALCmmdevProxy, void, closeProxy) \
+DECLARE_THUNK(T, ALCmmdevProxy, HRESULT, resetProxy) \
+DECLARE_THUNK(T, ALCmmdevProxy, HRESULT, startProxy) \
+DECLARE_THUNK(T, ALCmmdevProxy, void, stopProxy) \
+ \
+static const struct ALCmmdevProxyVtable T##_ALCmmdevProxy_vtable = { \
+ T##_ALCmmdevProxy_openProxy, \
+ T##_ALCmmdevProxy_closeProxy, \
+ T##_ALCmmdevProxy_resetProxy, \
+ T##_ALCmmdevProxy_startProxy, \
+ T##_ALCmmdevProxy_stopProxy, \
+}
+
+static void ALCmmdevProxy_Construct(ALCmmdevProxy* UNUSED(self)) { }
+static void ALCmmdevProxy_Destruct(ALCmmdevProxy* UNUSED(self)) { }
+
+static DWORD CALLBACK ALCmmdevProxy_messageHandler(void *ptr)
{
- ALCdevice *device = ptr;
- MMDevApiData *data = device->ExtraData;
+ ThreadRequest *req = ptr;
+ IMMDeviceEnumerator *Enumerator;
+ ALuint deviceCount = 0;
+ ALCmmdevProxy *proxy;
+ HRESULT hr, cohr;
+ MSG msg;
+
+ TRACE("Starting message thread\n");
+
+ cohr = CoInitialize(NULL);
+ if(FAILED(cohr))
+ {
+ WARN("Failed to initialize COM: 0x%08lx\n", cohr);
+ ReturnMsgResponse(req, cohr);
+ return 0;
+ }
+
+ hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
+ if(FAILED(hr))
+ {
+ WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr);
+ CoUninitialize();
+ ReturnMsgResponse(req, hr);
+ return 0;
+ }
+ Enumerator = ptr;
+ IMMDeviceEnumerator_Release(Enumerator);
+ Enumerator = NULL;
+
+ CoUninitialize();
+
+ /* HACK: Force Windows to create a message queue for this thread before
+ * returning success, otherwise PostThreadMessage may fail if it gets
+ * called before GetMessage.
+ */
+ PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+
+ TRACE("Message thread initialization complete\n");
+ ReturnMsgResponse(req, S_OK);
+
+ TRACE("Starting message loop\n");
+ while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last))
+ {
+ TRACE("Got message %u\n", msg.message);
+ switch(msg.message)
+ {
+ case WM_USER_OpenDevice:
+ req = (ThreadRequest*)msg.wParam;
+ proxy = (ALCmmdevProxy*)msg.lParam;
+
+ hr = cohr = S_OK;
+ if(++deviceCount == 1)
+ hr = cohr = CoInitialize(NULL);
+ if(SUCCEEDED(hr))
+ hr = V0(proxy,openProxy)();
+ if(FAILED(hr))
+ {
+ if(--deviceCount == 0 && SUCCEEDED(cohr))
+ CoUninitialize();
+ }
+
+ ReturnMsgResponse(req, hr);
+ continue;
+
+ case WM_USER_ResetDevice:
+ req = (ThreadRequest*)msg.wParam;
+ proxy = (ALCmmdevProxy*)msg.lParam;
+
+ hr = V0(proxy,resetProxy)();
+ ReturnMsgResponse(req, hr);
+ continue;
+
+ case WM_USER_StartDevice:
+ req = (ThreadRequest*)msg.wParam;
+ proxy = (ALCmmdevProxy*)msg.lParam;
+
+ hr = V0(proxy,startProxy)();
+ ReturnMsgResponse(req, hr);
+ continue;
+
+ case WM_USER_StopDevice:
+ req = (ThreadRequest*)msg.wParam;
+ proxy = (ALCmmdevProxy*)msg.lParam;
+
+ V0(proxy,stopProxy)();
+ ReturnMsgResponse(req, S_OK);
+ continue;
+
+ case WM_USER_CloseDevice:
+ req = (ThreadRequest*)msg.wParam;
+ proxy = (ALCmmdevProxy*)msg.lParam;
+
+ V0(proxy,closeProxy)();
+ if(--deviceCount == 0)
+ CoUninitialize();
+
+ ReturnMsgResponse(req, S_OK);
+ continue;
+
+ case WM_USER_Enumerate:
+ req = (ThreadRequest*)msg.wParam;
+
+ hr = cohr = S_OK;
+ if(++deviceCount == 1)
+ hr = cohr = CoInitialize(NULL);
+ if(SUCCEEDED(hr))
+ hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
+ if(SUCCEEDED(hr))
+ {
+ Enumerator = ptr;
+
+ if(msg.lParam == ALL_DEVICE_PROBE)
+ hr = probe_devices(Enumerator, eRender, &PlaybackDevices);
+ else if(msg.lParam == CAPTURE_DEVICE_PROBE)
+ hr = probe_devices(Enumerator, eCapture, &CaptureDevices);
+
+ IMMDeviceEnumerator_Release(Enumerator);
+ Enumerator = NULL;
+ }
+
+ if(--deviceCount == 0 && SUCCEEDED(cohr))
+ CoUninitialize();
+
+ ReturnMsgResponse(req, hr);
+ continue;
+
+ default:
+ ERR("Unexpected message: %u\n", msg.message);
+ continue;
+ }
+ }
+ TRACE("Message loop finished\n");
+
+ return 0;
+}
+
+
+typedef struct ALCmmdevPlayback {
+ DERIVE_FROM_TYPE(ALCbackend);
+ DERIVE_FROM_TYPE(ALCmmdevProxy);
+
+ WCHAR *devid;
+
+ IMMDevice *mmdev;
+ IAudioClient *client;
+ IAudioRenderClient *render;
+ HANDLE NotifyEvent;
+
+ HANDLE MsgEvent;
+
+ volatile UINT32 Padding;
+
+ volatile int killNow;
+ althrd_t thread;
+} ALCmmdevPlayback;
+
+static int ALCmmdevPlayback_mixerProc(void *arg);
+
+static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device);
+static void ALCmmdevPlayback_Destruct(ALCmmdevPlayback *self);
+static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *name);
+static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self);
+static void ALCmmdevPlayback_close(ALCmmdevPlayback *self);
+static void ALCmmdevPlayback_closeProxy(ALCmmdevPlayback *self);
+static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self);
+static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self);
+static ALCboolean ALCmmdevPlayback_start(ALCmmdevPlayback *self);
+static HRESULT ALCmmdevPlayback_startProxy(ALCmmdevPlayback *self);
+static void ALCmmdevPlayback_stop(ALCmmdevPlayback *self);
+static void ALCmmdevPlayback_stopProxy(ALCmmdevPlayback *self);
+static DECLARE_FORWARD2(ALCmmdevPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
+static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, ALCuint, availableSamples)
+static ALint64 ALCmmdevPlayback_getLatency(ALCmmdevPlayback *self);
+static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCmmdevPlayback)
+
+DEFINE_ALCMMDEVPROXY_VTABLE(ALCmmdevPlayback);
+DEFINE_ALCBACKEND_VTABLE(ALCmmdevPlayback);
+
+
+static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device)
+{
+ SET_VTABLE2(ALCmmdevPlayback, ALCbackend, self);
+ SET_VTABLE2(ALCmmdevPlayback, ALCmmdevProxy, self);
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ ALCmmdevProxy_Construct(STATIC_CAST(ALCmmdevProxy, self));
+
+ self->devid = NULL;
+
+ self->mmdev = NULL;
+ self->client = NULL;
+ self->render = NULL;
+ self->NotifyEvent = NULL;
+
+ self->MsgEvent = NULL;
+
+ self->Padding = 0;
+
+ self->killNow = 0;
+}
+
+static void ALCmmdevPlayback_Destruct(ALCmmdevPlayback *self)
+{
+ if(self->NotifyEvent != NULL)
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
+ if(self->MsgEvent != NULL)
+ CloseHandle(self->MsgEvent);
+ self->MsgEvent = NULL;
+
+ free(self->devid);
+ self->devid = NULL;
+
+ ALCmmdevProxy_Destruct(STATIC_CAST(ALCmmdevProxy, self));
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
+{
+ ALCmmdevPlayback *self = arg;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
UINT32 buffer_len, written;
ALuint update_size, len;
BYTE *buffer;
@@ -236,17 +486,17 @@ FORCE_ALIGN static ALuint MMDevApiProc(ALvoid *ptr)
ALCdevice_Lock(device);
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
- return 0;
+ return 1;
}
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
update_size = device->UpdateSize;
buffer_len = update_size * device->NumUpdates;
- while(!data->killNow)
+ while(!self->killNow)
{
- hr = IAudioClient_GetCurrentPadding(data->client, &written);
+ hr = IAudioClient_GetCurrentPadding(self->client, &written);
if(FAILED(hr))
{
ERR("Failed to get padding: 0x%08lx\n", hr);
@@ -255,27 +505,27 @@ FORCE_ALIGN static ALuint MMDevApiProc(ALvoid *ptr)
ALCdevice_Unlock(device);
break;
}
- data->Padding = written;
+ self->Padding = written;
len = buffer_len - written;
if(len < update_size)
{
DWORD res;
- res = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE);
+ res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE);
if(res != WAIT_OBJECT_0)
ERR("WaitForSingleObjectEx error: 0x%lx\n", res);
continue;
}
len -= len%update_size;
- hr = IAudioRenderClient_GetBuffer(data->render, len, &buffer);
+ hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer);
if(SUCCEEDED(hr))
{
ALCdevice_Lock(device);
aluMixData(device, buffer, len);
- data->Padding = written + len;
+ self->Padding = written + len;
ALCdevice_Unlock(device);
- hr = IAudioRenderClient_ReleaseBuffer(data->render, len, 0);
+ hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0);
}
if(FAILED(hr))
{
@@ -286,7 +536,7 @@ FORCE_ALIGN static ALuint MMDevApiProc(ALvoid *ptr)
break;
}
}
- data->Padding = 0;
+ self->Padding = 0;
CoUninitialize();
return 0;
@@ -332,16 +582,178 @@ static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *
return ALC_TRUE;
}
-static HRESULT DoReset(ALCdevice *device)
+
+static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *deviceName)
+{
+ HRESULT hr = S_OK;
+
+ self->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ self->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if(self->NotifyEvent == NULL || self->MsgEvent == NULL)
+ {
+ ERR("Failed to create message events: %lu\n", GetLastError());
+ hr = E_FAIL;
+ }
+
+ if(SUCCEEDED(hr))
+ {
+ if(deviceName)
+ {
+ const DevMap *iter, *end;
+
+ if(VECTOR_SIZE(PlaybackDevices) == 0)
+ {
+ ThreadRequest req = { self->MsgEvent, 0 };
+ if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE))
+ (void)WaitForResponse(&req);
+ }
+
+ hr = E_FAIL;
+ iter = VECTOR_ITER_BEGIN(PlaybackDevices);
+ end = VECTOR_ITER_END(PlaybackDevices);
+ for(;iter != end;iter++)
+ {
+ if(al_string_cmp_cstr(iter->name, deviceName) == 0)
+ {
+ self->devid = strdupW(iter->devid);
+ hr = S_OK;
+ break;
+ }
+ }
+ if(FAILED(hr))
+ WARN("Failed to find device name matching \"%s\"\n", deviceName);
+ }
+ }
+
+ if(SUCCEEDED(hr))
+ {
+ ThreadRequest req = { self->MsgEvent, 0 };
+
+ hr = E_FAIL;
+ if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ hr = WaitForResponse(&req);
+ else
+ ERR("Failed to post thread message: %lu\n", GetLastError());
+ }
+
+ if(FAILED(hr))
+ {
+ if(self->NotifyEvent != NULL)
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
+ if(self->MsgEvent != NULL)
+ CloseHandle(self->MsgEvent);
+ self->MsgEvent = NULL;
+
+ free(self->devid);
+ self->devid = NULL;
+
+ ERR("Device init failed: 0x%08lx\n", hr);
+ return ALC_INVALID_VALUE;
+ }
+
+ return ALC_NO_ERROR;
+}
+
+static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ void *ptr;
+ HRESULT hr;
+
+ hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
+ if(SUCCEEDED(hr))
+ {
+ IMMDeviceEnumerator *Enumerator = ptr;
+ if(!self->devid)
+ hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &self->mmdev);
+ else
+ hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev);
+ IMMDeviceEnumerator_Release(Enumerator);
+ Enumerator = NULL;
+ }
+ if(SUCCEEDED(hr))
+ hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
+ if(SUCCEEDED(hr))
+ {
+ self->client = ptr;
+ get_device_name(self->mmdev, &device->DeviceName);
+ }
+
+ if(FAILED(hr))
+ {
+ if(self->mmdev)
+ IMMDevice_Release(self->mmdev);
+ self->mmdev = NULL;
+ }
+
+ return hr;
+}
+
+
+static void ALCmmdevPlayback_close(ALCmmdevPlayback *self)
+{
+ ThreadRequest req = { self->MsgEvent, 0 };
+
+ if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ (void)WaitForResponse(&req);
+
+ CloseHandle(self->MsgEvent);
+ self->MsgEvent = NULL;
+
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
+
+ free(self->devid);
+ self->devid = NULL;
+}
+
+static void ALCmmdevPlayback_closeProxy(ALCmmdevPlayback *self)
{
- MMDevApiData *data = device->ExtraData;
+ if(self->client)
+ IAudioClient_Release(self->client);
+ self->client = NULL;
+
+ if(self->mmdev)
+ IMMDevice_Release(self->mmdev);
+ self->mmdev = NULL;
+}
+
+
+static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self)
+{
+ ThreadRequest req = { self->MsgEvent, 0 };
+ HRESULT hr = E_FAIL;
+
+ if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ hr = WaitForResponse(&req);
+
+ return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
+}
+
+static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
WAVEFORMATEXTENSIBLE OutputType;
WAVEFORMATEX *wfx = NULL;
REFERENCE_TIME min_per, buf_time;
UINT32 buffer_len, min_len;
+ void *ptr = NULL;
HRESULT hr;
- hr = IAudioClient_GetMixFormat(data->client, &wfx);
+ if(self->client)
+ IAudioClient_Release(self->client);
+ self->client = NULL;
+
+ hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
+ if(FAILED(hr))
+ {
+ ERR("Failed to reactivate audio client: 0x%08lx\n", hr);
+ return hr;
+ }
+ self->client = ptr;
+
+ hr = IAudioClient_GetMixFormat(self->client, &wfx);
if(FAILED(hr))
{
ERR("Failed to get mix format: 0x%08lx\n", hr);
@@ -451,11 +863,11 @@ static HRESULT DoReset(ALCdevice *device)
OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec *
OutputType.Format.nBlockAlign;
- hr = IAudioClient_IsFormatSupported(data->client, AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx);
+ hr = IAudioClient_IsFormatSupported(self->client, AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx);
if(FAILED(hr))
{
ERR("Failed to check format support: 0x%08lx\n", hr);
- hr = IAudioClient_GetMixFormat(data->client, &wfx);
+ hr = IAudioClient_GetMixFormat(self->client, &wfx);
}
if(FAILED(hr))
{
@@ -527,7 +939,7 @@ static HRESULT DoReset(ALCdevice *device)
SetDefaultWFXChannelOrder(device);
- hr = IAudioClient_Initialize(data->client, AUDCLNT_SHAREMODE_SHARED,
+ hr = IAudioClient_Initialize(self->client, AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
buf_time, 0, &OutputType.Format, NULL);
if(FAILED(hr))
@@ -536,14 +948,14 @@ static HRESULT DoReset(ALCdevice *device)
return hr;
}
- hr = IAudioClient_GetDevicePeriod(data->client, &min_per, NULL);
+ hr = IAudioClient_GetDevicePeriod(self->client, &min_per, NULL);
if(SUCCEEDED(hr))
{
min_len = (UINT32)((min_per*device->Frequency + 10000000-1) / 10000000);
/* Find the nearest multiple of the period size to the update size */
if(min_len < device->UpdateSize)
min_len *= (device->UpdateSize + min_len/2)/min_len;
- hr = IAudioClient_GetBufferSize(data->client, &buffer_len);
+ hr = IAudioClient_GetBufferSize(self->client, &buffer_len);
}
if(FAILED(hr))
{
@@ -560,247 +972,106 @@ static HRESULT DoReset(ALCdevice *device)
device->UpdateSize = buffer_len / device->NumUpdates;
}
+ hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent);
+ if(FAILED(hr))
+ {
+ ERR("Failed to set event handle: 0x%08lx\n", hr);
+ return hr;
+ }
+
return hr;
}
-static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
+static ALCboolean ALCmmdevPlayback_start(ALCmmdevPlayback *self)
{
- ThreadRequest *req = ptr;
- IMMDeviceEnumerator *Enumerator;
- ALuint deviceCount = 0;
- MMDevApiData *data;
- ALCdevice *device;
- HRESULT hr, cohr;
- MSG msg;
-
- TRACE("Starting message thread\n");
-
- cohr = CoInitialize(NULL);
- if(FAILED(cohr))
- {
- WARN("Failed to initialize COM: 0x%08lx\n", cohr);
- req->result = cohr;
- SetEvent(req->FinishedEvt);
- return 0;
- }
+ ThreadRequest req = { self->MsgEvent, 0 };
+ HRESULT hr = E_FAIL;
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
- if(FAILED(hr))
- {
- WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr);
- CoUninitialize();
- req->result = hr;
- SetEvent(req->FinishedEvt);
- return 0;
- }
- Enumerator = ptr;
- IMMDeviceEnumerator_Release(Enumerator);
- Enumerator = NULL;
+ if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ hr = WaitForResponse(&req);
- CoUninitialize();
+ return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
+}
- /* HACK: Force Windows to create a message queue for this thread before
- * returning success, otherwise PostThreadMessage may fail if it gets
- * called before GetMessage.
- */
- PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+static HRESULT ALCmmdevPlayback_startProxy(ALCmmdevPlayback *self)
+{
+ HRESULT hr;
+ void *ptr;
- TRACE("Message thread initialization complete\n");
- req->result = S_OK;
- SetEvent(req->FinishedEvt);
+ ResetEvent(self->NotifyEvent);
+ hr = IAudioClient_Start(self->client);
+ if(FAILED(hr))
+ ERR("Failed to start audio client: 0x%08lx\n", hr);
- TRACE("Starting message loop\n");
- while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last))
+ if(SUCCEEDED(hr))
+ hr = IAudioClient_GetService(self->client, &IID_IAudioRenderClient, &ptr);
+ if(SUCCEEDED(hr))
{
- TRACE("Got message %u\n", msg.message);
- switch(msg.message)
+ self->render = ptr;
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCmmdevPlayback_mixerProc, self) != althrd_success)
{
- case WM_USER_OpenDevice:
- req = (ThreadRequest*)msg.wParam;
- device = (ALCdevice*)msg.lParam;
- data = device->ExtraData;
-
- hr = cohr = S_OK;
- if(++deviceCount == 1)
- hr = cohr = CoInitialize(NULL);
- if(SUCCEEDED(hr))
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
- if(SUCCEEDED(hr))
- {
- Enumerator = ptr;
- if(!data->devid)
- hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &data->mmdev);
- else
- hr = IMMDeviceEnumerator_GetDevice(Enumerator, data->devid, &data->mmdev);
- IMMDeviceEnumerator_Release(Enumerator);
- Enumerator = NULL;
- }
- if(SUCCEEDED(hr))
- hr = IMMDevice_Activate(data->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
- if(SUCCEEDED(hr))
- {
- data->client = ptr;
- device->DeviceName = get_device_name(data->mmdev);
- }
-
- if(FAILED(hr))
- {
- if(data->mmdev)
- IMMDevice_Release(data->mmdev);
- data->mmdev = NULL;
- if(--deviceCount == 0 && SUCCEEDED(cohr))
- CoUninitialize();
- }
-
- req->result = hr;
- SetEvent(req->FinishedEvt);
- continue;
-
- case WM_USER_ResetDevice:
- req = (ThreadRequest*)msg.wParam;
- device = (ALCdevice*)msg.lParam;
-
- req->result = DoReset(device);
- SetEvent(req->FinishedEvt);
- continue;
-
- case WM_USER_StartDevice:
- req = (ThreadRequest*)msg.wParam;
- device = (ALCdevice*)msg.lParam;
- data = device->ExtraData;
-
- ResetEvent(data->NotifyEvent);
- hr = IAudioClient_SetEventHandle(data->client, data->NotifyEvent);
- if(FAILED(hr))
- ERR("Failed to set event handle: 0x%08lx\n", hr);
- else
- {
- hr = IAudioClient_Start(data->client);
- if(FAILED(hr))
- ERR("Failed to start audio client: 0x%08lx\n", hr);
- }
-
- if(SUCCEEDED(hr))
- hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &ptr);
- if(SUCCEEDED(hr))
- {
- data->render = ptr;
- if(!StartThread(&data->thread, MMDevApiProc, device))
- {
- if(data->render)
- IAudioRenderClient_Release(data->render);
- data->render = NULL;
- IAudioClient_Stop(data->client);
- ERR("Failed to start thread\n");
- hr = E_FAIL;
- }
- }
-
- req->result = hr;
- SetEvent(req->FinishedEvt);
- continue;
-
- case WM_USER_StopDevice:
- req = (ThreadRequest*)msg.wParam;
- device = (ALCdevice*)msg.lParam;
- data = device->ExtraData;
-
- if(data->thread)
- {
- data->killNow = 1;
- StopThread(data->thread);
- data->thread = NULL;
-
- data->killNow = 0;
-
- IAudioRenderClient_Release(data->render);
- data->render = NULL;
- IAudioClient_Stop(data->client);
- }
+ if(self->render)
+ IAudioRenderClient_Release(self->render);
+ self->render = NULL;
+ IAudioClient_Stop(self->client);
+ ERR("Failed to start thread\n");
+ hr = E_FAIL;
+ }
+ }
- req->result = S_OK;
- SetEvent(req->FinishedEvt);
- continue;
+ return hr;
+}
- case WM_USER_CloseDevice:
- req = (ThreadRequest*)msg.wParam;
- device = (ALCdevice*)msg.lParam;
- data = device->ExtraData;
- IAudioClient_Release(data->client);
- data->client = NULL;
+static void ALCmmdevPlayback_stop(ALCmmdevPlayback *self)
+{
+ ThreadRequest req = { self->MsgEvent, 0 };
+ if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ (void)WaitForResponse(&req);
+}
- IMMDevice_Release(data->mmdev);
- data->mmdev = NULL;
+static void ALCmmdevPlayback_stopProxy(ALCmmdevPlayback *self)
+{
+ int res;
- if(--deviceCount == 0)
- CoUninitialize();
+ if(!self->render)
+ return;
- req->result = S_OK;
- SetEvent(req->FinishedEvt);
- continue;
+ self->killNow = 1;
+ althrd_join(self->thread, &res);
- case WM_USER_Enumerate:
- req = (ThreadRequest*)msg.wParam;
-
- hr = cohr = S_OK;
- if(++deviceCount == 1)
- hr = cohr = CoInitialize(NULL);
- if(SUCCEEDED(hr))
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
- if(SUCCEEDED(hr))
- {
- EDataFlow flowdir;
- DevMap **devlist;
- ALuint *numdevs;
- ALuint i;
-
- Enumerator = ptr;
- if(msg.lParam == CAPTURE_DEVICE_PROBE)
- {
- flowdir = eCapture;
- devlist = &CaptureDeviceList;
- numdevs = &NumCaptureDevices;
- }
- else
- {
- flowdir = eRender;
- devlist = &PlaybackDeviceList;
- numdevs = &NumPlaybackDevices;
- }
+ IAudioRenderClient_Release(self->render);
+ self->render = NULL;
+ IAudioClient_Stop(self->client);
+}
- for(i = 0;i < *numdevs;i++)
- {
- free((*devlist)[i].name);
- free((*devlist)[i].devid);
- }
- free(*devlist);
- *devlist = NULL;
- *numdevs = 0;
- *devlist = ProbeDevices(Enumerator, flowdir, numdevs);
+static ALint64 ALCmmdevPlayback_getLatency(ALCmmdevPlayback *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ return (ALint64)self->Padding * 1000000000 / device->Frequency;
+}
- IMMDeviceEnumerator_Release(Enumerator);
- Enumerator = NULL;
- }
- if(--deviceCount == 0 && SUCCEEDED(cohr))
- CoUninitialize();
+static inline void AppendAllDevicesList2(const DevMap *entry)
+{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
+static inline void AppendCaptureDeviceList2(const DevMap *entry)
+{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
- req->result = S_OK;
- SetEvent(req->FinishedEvt);
- continue;
+typedef struct ALCmmdevBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCmmdevBackendFactory;
+#define ALCMMDEVBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCmmdevBackendFactory, ALCbackendFactory) } }
- default:
- ERR("Unexpected message: %u\n", msg.message);
- continue;
- }
- }
- TRACE("Message loop finished\n");
+static ALCboolean ALCmmdevBackendFactory_init(ALCmmdevBackendFactory *self);
+static void ALCmmdevBackendFactory_deinit(ALCmmdevBackendFactory *self);
+static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory *self, ALCbackend_Type type);
+static void ALCmmdevBackendFactory_probe(ALCmmdevBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
- return 0;
-}
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCmmdevBackendFactory);
static BOOL MMDevApiLoad(void)
@@ -816,7 +1087,7 @@ static BOOL MMDevApiLoad(void)
ERR("Failed to create event: %lu\n", GetLastError());
else
{
- ThreadHdl = CreateThread(NULL, 0, MMDevApiMsgProc, &req, 0, &ThreadID);
+ ThreadHdl = CreateThread(NULL, 0, ALCmmdevProxy_messageHandler, &req, 0, &ThreadID);
if(ThreadHdl != NULL)
InitResult = WaitForResponse(&req);
CloseHandle(req.FinishedEvt);
@@ -825,196 +1096,23 @@ static BOOL MMDevApiLoad(void)
return SUCCEEDED(InitResult);
}
-
-static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
-{
- MMDevApiData *data = NULL;
- HRESULT hr;
-
- //Initialise requested device
- data = calloc(1, sizeof(MMDevApiData));
- if(!data)
- return ALC_OUT_OF_MEMORY;
- device->ExtraData = data;
-
- hr = S_OK;
- data->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- data->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if(data->NotifyEvent == NULL || data->MsgEvent == NULL)
- {
- ERR("Failed to create message events: %lu\n", GetLastError());
- hr = E_FAIL;
- }
-
- if(SUCCEEDED(hr))
- {
- if(deviceName)
- {
- ALuint i;
-
- if(!PlaybackDeviceList)
- {
- ThreadRequest req = { data->MsgEvent, 0 };
- if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE))
- (void)WaitForResponse(&req);
- }
-
- hr = E_FAIL;
- for(i = 0;i < NumPlaybackDevices;i++)
- {
- if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
- {
- data->devid = strdupW(PlaybackDeviceList[i].devid);
- hr = S_OK;
- break;
- }
- }
- if(FAILED(hr))
- WARN("Failed to find device name matching \"%s\"\n", deviceName);
- }
- }
-
- if(SUCCEEDED(hr))
- {
- ThreadRequest req = { data->MsgEvent, 0 };
-
- hr = E_FAIL;
- if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)device))
- hr = WaitForResponse(&req);
- else
- ERR("Failed to post thread message: %lu\n", GetLastError());
- }
-
- if(FAILED(hr))
- {
- if(data->NotifyEvent != NULL)
- CloseHandle(data->NotifyEvent);
- data->NotifyEvent = NULL;
- if(data->MsgEvent != NULL)
- CloseHandle(data->MsgEvent);
- data->MsgEvent = NULL;
-
- free(data->devid);
- data->devid = NULL;
-
- free(data);
- device->ExtraData = NULL;
-
- ERR("Device init failed: 0x%08lx\n", hr);
- return ALC_INVALID_VALUE;
- }
-
- return ALC_NO_ERROR;
-}
-
-static void MMDevApiClosePlayback(ALCdevice *device)
-{
- MMDevApiData *data = device->ExtraData;
- ThreadRequest req = { data->MsgEvent, 0 };
-
- if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)device))
- (void)WaitForResponse(&req);
-
- CloseHandle(data->MsgEvent);
- data->MsgEvent = NULL;
-
- CloseHandle(data->NotifyEvent);
- data->NotifyEvent = NULL;
-
- free(data->devid);
- data->devid = NULL;
-
- free(data);
- device->ExtraData = NULL;
-}
-
-static ALCboolean MMDevApiResetPlayback(ALCdevice *device)
-{
- MMDevApiData *data = device->ExtraData;
- ThreadRequest req = { data->MsgEvent, 0 };
- HRESULT hr = E_FAIL;
-
- if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)device))
- hr = WaitForResponse(&req);
-
- return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
-}
-
-static ALCboolean MMDevApiStartPlayback(ALCdevice *device)
+static ALCboolean ALCmmdevBackendFactory_init(ALCmmdevBackendFactory* UNUSED(self))
{
- MMDevApiData *data = device->ExtraData;
- ThreadRequest req = { data->MsgEvent, 0 };
- HRESULT hr = E_FAIL;
-
- if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)device))
- hr = WaitForResponse(&req);
-
- return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
-}
-
-static void MMDevApiStopPlayback(ALCdevice *device)
-{
- MMDevApiData *data = device->ExtraData;
- ThreadRequest req = { data->MsgEvent, 0 };
-
- if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)device))
- (void)WaitForResponse(&req);
-}
-
-
-static ALint64 MMDevApiGetLatency(ALCdevice *device)
-{
- MMDevApiData *data = device->ExtraData;
-
- return (ALint64)data->Padding * 1000000000 / device->Frequency;
-}
-
-
-static const BackendFuncs MMDevApiFuncs = {
- MMDevApiOpenPlayback,
- MMDevApiClosePlayback,
- MMDevApiResetPlayback,
- MMDevApiStartPlayback,
- MMDevApiStopPlayback,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- MMDevApiGetLatency
-};
+ VECTOR_INIT(PlaybackDevices);
+ VECTOR_INIT(CaptureDevices);
-
-ALCboolean alcMMDevApiInit(BackendFuncs *FuncList)
-{
if(!MMDevApiLoad())
return ALC_FALSE;
- *FuncList = MMDevApiFuncs;
return ALC_TRUE;
}
-void alcMMDevApiDeinit(void)
+static void ALCmmdevBackendFactory_deinit(ALCmmdevBackendFactory* UNUSED(self))
{
- ALuint i;
+ clear_devlist(&PlaybackDevices);
+ VECTOR_DEINIT(PlaybackDevices);
- for(i = 0;i < NumPlaybackDevices;i++)
- {
- free(PlaybackDeviceList[i].name);
- free(PlaybackDeviceList[i].devid);
- }
- free(PlaybackDeviceList);
- PlaybackDeviceList = NULL;
- NumPlaybackDevices = 0;
-
- for(i = 0;i < NumCaptureDevices;i++)
- {
- free(CaptureDeviceList[i].name);
- free(CaptureDeviceList[i].devid);
- }
- free(CaptureDeviceList);
- CaptureDeviceList = NULL;
- NumCaptureDevices = 0;
+ clear_devlist(&CaptureDevices);
+ VECTOR_DEINIT(CaptureDevices);
if(ThreadHdl)
{
@@ -1025,34 +1123,61 @@ void alcMMDevApiDeinit(void)
}
}
-void alcMMDevApiProbe(enum DevProbe type)
+static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ return ALC_TRUE;
+ return ALC_FALSE;
+}
+
+static void ALCmmdevBackendFactory_probe(ALCmmdevBackendFactory* UNUSED(self), enum DevProbe type)
{
ThreadRequest req = { NULL, 0 };
- HRESULT hr = E_FAIL;
- switch(type)
+ req.FinishedEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if(req.FinishedEvt == NULL)
+ ERR("Failed to create event: %lu\n", GetLastError());
+ else
{
+ HRESULT hr = E_FAIL;
+ if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, type))
+ hr = WaitForResponse(&req);
+ if(SUCCEEDED(hr)) switch(type)
+ {
case ALL_DEVICE_PROBE:
- req.FinishedEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
- if(req.FinishedEvt == NULL)
- ERR("Failed to create event: %lu\n", GetLastError());
- else if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, type))
- hr = WaitForResponse(&req);
- if(SUCCEEDED(hr))
- {
- ALuint i;
- for(i = 0;i < NumPlaybackDevices;i++)
- {
- if(PlaybackDeviceList[i].name)
- AppendAllDevicesList(PlaybackDeviceList[i].name);
- }
- }
+ VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
+ VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
break;
- }
- if(req.FinishedEvt != NULL)
+ }
CloseHandle(req.FinishedEvt);
- req.FinishedEvt = NULL;
+ req.FinishedEvt = NULL;
+ }
+}
+
+static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCmmdevPlayback *backend;
+
+ backend = ALCmmdevPlayback_New(sizeof(*backend));
+ if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
+
+ ALCmmdevPlayback_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
+
+
+ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void)
+{
+ static ALCmmdevBackendFactory factory = ALCMMDEVBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
}
diff --git a/Alc/backends/null.c b/Alc/backends/null.c
index a7056369..3f09c5d6 100644
--- a/Alc/backends/null.c
+++ b/Alc/backends/null.c
@@ -37,11 +37,10 @@ typedef struct ALCnullBackend {
DERIVE_FROM_TYPE(ALCbackend);
volatile int killNow;
- althread_t thread;
+ althrd_t thread;
} ALCnullBackend;
-DECLARE_ALCBACKEND_VTABLE(ALCnullBackend);
-static ALuint ALCnullBackend_mixerProc(ALvoid *ptr);
+static int ALCnullBackend_mixerProc(void *ptr);
static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device);
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, Destruct)
@@ -55,6 +54,10 @@ static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCnullBackend)
+
+DEFINE_ALCBACKEND_VTABLE(ALCnullBackend);
+
static const ALCchar nullDevice[] = "No Output";
@@ -66,42 +69,49 @@ static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device)
}
-static ALuint ALCnullBackend_mixerProc(ALvoid *ptr)
+static int ALCnullBackend_mixerProc(void *ptr)
{
ALCnullBackend *self = (ALCnullBackend*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- ALuint now, start;
+ struct timespec now, start;
ALuint64 avail, done;
+ const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 /
+ device->Frequency / 2);
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
done = 0;
- start = timeGetTime();
+ if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC)
+ {
+ ERR("Failed to get starting time\n");
+ return 1;
+ }
while(!self->killNow && device->Connected)
{
- now = timeGetTime();
+ if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
+ {
+ ERR("Failed to get current time\n");
+ return 1;
+ }
- avail = (ALuint64)(now-start) * device->Frequency / 1000;
+ avail = (now.tv_sec - start.tv_sec) * device->Frequency;
+ avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000;
if(avail < done)
{
- /* Timer wrapped (50 days???). Add the remainder of the cycle to
- * the available count and reset the number of samples done */
- avail += (U64(1)<<32)*device->Frequency/1000 - done;
- done = 0;
+ /* Oops, time skipped backwards. Reset the number of samples done
+ * with one update available since we (likely) just came back from
+ * sleeping. */
+ done = avail - device->UpdateSize;
}
+
if(avail-done < device->UpdateSize)
+ al_nssleep(0, restTime);
+ else while(avail-done >= device->UpdateSize)
{
- ALuint restTime = (ALuint)((device->UpdateSize - (avail-done)) * 1000 /
- device->Frequency);
- Sleep(restTime);
- continue;
- }
-
- do {
aluMixData(device, NULL, device->UpdateSize);
done += device->UpdateSize;
- } while(avail-done >= device->UpdateSize);
+ }
}
return 0;
@@ -118,7 +128,7 @@ static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name)
return ALC_INVALID_VALUE;
device = STATIC_CAST(ALCbackend, self)->mDevice;
- device->DeviceName = strdup(name);
+ al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
@@ -135,31 +145,23 @@ static ALCboolean ALCnullBackend_reset(ALCnullBackend *self)
static ALCboolean ALCnullBackend_start(ALCnullBackend *self)
{
- if(!StartThread(&self->thread, ALCnullBackend_mixerProc, self))
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
}
static void ALCnullBackend_stop(ALCnullBackend *self)
{
- if(!self->thread)
+ int res;
+
+ if(self->killNow)
return;
self->killNow = 1;
- StopThread(self->thread);
- self->thread = NULL;
-
- self->killNow = 0;
-}
-
-
-static void ALCnullBackend_Delete(ALCnullBackend *self)
-{
- free(self);
+ althrd_join(self->thread, &res);
}
-DEFINE_ALCBACKEND_VTABLE(ALCnullBackend);
-
typedef struct ALCnullBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
@@ -209,14 +211,18 @@ static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enu
static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
- ALCnullBackend *backend;
+ if(type == ALCbackend_Playback)
+ {
+ ALCnullBackend *backend;
- assert(type == ALCbackend_Playback);
+ backend = ALCnullBackend_New(sizeof(*backend));
+ if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
- backend = calloc(1, sizeof(*backend));
- if(!backend) return NULL;
+ ALCnullBackend_Construct(backend, device);
- ALCnullBackend_Construct(backend, device);
+ return STATIC_CAST(ALCbackend, backend);
+ }
- return STATIC_CAST(ALCbackend, backend);
+ return NULL;
}
diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c
index 76cbaf1a..220e6e5c 100644
--- a/Alc/backends/opensl.c
+++ b/Alc/backends/opensl.c
@@ -28,62 +28,9 @@
#include <SLES/OpenSLES.h>
-#if 1
#include <SLES/OpenSLES_Android.h>
-#else
-extern SLAPIENTRY const SLInterfaceID SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
-
-struct SLAndroidSimpleBufferQueueItf_;
-typedef const struct SLAndroidSimpleBufferQueueItf_ * const * SLAndroidSimpleBufferQueueItf;
-
-typedef void (*slAndroidSimpleBufferQueueCallback)(SLAndroidSimpleBufferQueueItf caller, void *pContext);
-
-typedef struct SLAndroidSimpleBufferQueueState_ {
- SLuint32 count;
- SLuint32 index;
-} SLAndroidSimpleBufferQueueState;
-
-
-struct SLAndroidSimpleBufferQueueItf_ {
- SLresult (*Enqueue) (
- SLAndroidSimpleBufferQueueItf self,
- const void *pBuffer,
- SLuint32 size
- );
- SLresult (*Clear) (
- SLAndroidSimpleBufferQueueItf self
- );
- SLresult (*GetState) (
- SLAndroidSimpleBufferQueueItf self,
- SLAndroidSimpleBufferQueueState *pState
- );
- SLresult (*RegisterCallback) (
- SLAndroidSimpleBufferQueueItf self,
- slAndroidSimpleBufferQueueCallback callback,
- void* pContext
- );
-};
-
-#define SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE ((SLuint32) 0x800007BD)
-
-typedef struct SLDataLocator_AndroidSimpleBufferQueue {
- SLuint32 locatorType;
- SLuint32 numBuffers;
-} SLDataLocator_AndroidSimpleBufferQueue;
-
-#endif
/* Helper macros */
-#define SLObjectItf_Realize(a,b) ((*(a))->Realize((a),(b)))
-#define SLObjectItf_GetInterface(a,b,c) ((*(a))->GetInterface((a),(b),(c)))
-#define SLObjectItf_Destroy(a) ((*(a))->Destroy((a)))
-
-#define SLEngineItf_CreateOutputMix(a,b,c,d,e) ((*(a))->CreateOutputMix((a),(b),(c),(d),(e)))
-#define SLEngineItf_CreateAudioPlayer(a,b,c,d,e,f,g) ((*(a))->CreateAudioPlayer((a),(b),(c),(d),(e),(f),(g)))
-
-#define SLPlayItf_SetPlayState(a,b) ((*(a))->SetPlayState((a),(b)))
-
-/* Should start using these generic callers instead of the name-specific ones above. */
#define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
#define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
@@ -186,7 +133,7 @@ static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context)
buf = (ALbyte*)data->buffer + data->curBuffer*data->bufferSize;
aluMixData(Device, buf, data->bufferSize/data->frameSize);
- result = (*bq)->Enqueue(bq, buf, data->bufferSize);
+ result = VCALL(bq,Enqueue)(buf, data->bufferSize);
PRINTERR(result, "bq->Enqueue");
data->curBuffer = (data->curBuffer+1) % Device->NumUpdates;
@@ -212,33 +159,33 @@ static ALCenum opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName
PRINTERR(result, "slCreateEngine");
if(SL_RESULT_SUCCESS == result)
{
- result = SLObjectItf_Realize(data->engineObject, SL_BOOLEAN_FALSE);
+ result = VCALL(data->engineObject,Realize)(SL_BOOLEAN_FALSE);
PRINTERR(result, "engine->Realize");
}
if(SL_RESULT_SUCCESS == result)
{
- result = SLObjectItf_GetInterface(data->engineObject, SL_IID_ENGINE, &data->engine);
+ result = VCALL(data->engineObject,GetInterface)(SL_IID_ENGINE, &data->engine);
PRINTERR(result, "engine->GetInterface");
}
if(SL_RESULT_SUCCESS == result)
{
- result = SLEngineItf_CreateOutputMix(data->engine, &data->outputMix, 0, NULL, NULL);
+ result = VCALL(data->engine,CreateOutputMix)(&data->outputMix, 0, NULL, NULL);
PRINTERR(result, "engine->CreateOutputMix");
}
if(SL_RESULT_SUCCESS == result)
{
- result = SLObjectItf_Realize(data->outputMix, SL_BOOLEAN_FALSE);
+ result = VCALL(data->outputMix,Realize)(SL_BOOLEAN_FALSE);
PRINTERR(result, "outputMix->Realize");
}
if(SL_RESULT_SUCCESS != result)
{
if(data->outputMix != NULL)
- SLObjectItf_Destroy(data->outputMix);
+ VCALL0(data->outputMix,Destroy)();
data->outputMix = NULL;
if(data->engineObject != NULL)
- SLObjectItf_Destroy(data->engineObject);
+ VCALL0(data->engineObject,Destroy)();
data->engineObject = NULL;
data->engine = NULL;
@@ -246,7 +193,7 @@ static ALCenum opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName
return ALC_INVALID_VALUE;
}
- Device->DeviceName = strdup(deviceName);
+ al_string_copy_cstr(&Device->DeviceName, deviceName);
Device->ExtraData = data;
return ALC_NO_ERROR;
@@ -258,13 +205,13 @@ static void opensl_close_playback(ALCdevice *Device)
osl_data *data = Device->ExtraData;
if(data->bufferQueueObject != NULL)
- SLObjectItf_Destroy(data->bufferQueueObject);
+ VCALL0(data->bufferQueueObject,Destroy)();
data->bufferQueueObject = NULL;
- SLObjectItf_Destroy(data->outputMix);
+ VCALL0(data->outputMix,Destroy)();
data->outputMix = NULL;
- SLObjectItf_Destroy(data->engineObject);
+ VCALL0(data->engineObject,Destroy)();
data->engineObject = NULL;
data->engine = NULL;
@@ -321,21 +268,21 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device)
if(data->bufferQueueObject != NULL)
- SLObjectItf_Destroy(data->bufferQueueObject);
+ VCALL0(data->bufferQueueObject,Destroy)();
data->bufferQueueObject = NULL;
- result = SLEngineItf_CreateAudioPlayer(data->engine, &data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req);
+ result = VCALL(data->engine,CreateAudioPlayer)(&data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req);
PRINTERR(result, "engine->CreateAudioPlayer");
if(SL_RESULT_SUCCESS == result)
{
- result = SLObjectItf_Realize(data->bufferQueueObject, SL_BOOLEAN_FALSE);
+ result = VCALL(data->bufferQueueObject,Realize)(SL_BOOLEAN_FALSE);
PRINTERR(result, "bufferQueue->Realize");
}
if(SL_RESULT_SUCCESS != result)
{
if(data->bufferQueueObject != NULL)
- SLObjectItf_Destroy(data->bufferQueueObject);
+ VCALL0(data->bufferQueueObject,Destroy)();
data->bufferQueueObject = NULL;
return ALC_FALSE;
@@ -352,11 +299,11 @@ static ALCboolean opensl_start_playback(ALCdevice *Device)
SLresult result;
ALuint i;
- result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_BUFFERQUEUE, &bufferQueue);
+ result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue);
PRINTERR(result, "bufferQueue->GetInterface");
if(SL_RESULT_SUCCESS == result)
{
- result = (*bufferQueue)->RegisterCallback(bufferQueue, opensl_callback, Device);
+ result = VCALL(bufferQueue,RegisterCallback)(opensl_callback, Device);
PRINTERR(result, "bufferQueue->RegisterCallback");
}
if(SL_RESULT_SUCCESS == result)
@@ -376,26 +323,26 @@ static ALCboolean opensl_start_playback(ALCdevice *Device)
if(SL_RESULT_SUCCESS == result)
{
ALvoid *buf = (ALbyte*)data->buffer + i*data->bufferSize;
- result = (*bufferQueue)->Enqueue(bufferQueue, buf, data->bufferSize);
+ result = VCALL(bufferQueue,Enqueue)(buf, data->bufferSize);
PRINTERR(result, "bufferQueue->Enqueue");
}
}
data->curBuffer = 0;
if(SL_RESULT_SUCCESS == result)
{
- result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_PLAY, &player);
+ result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_PLAY, &player);
PRINTERR(result, "bufferQueue->GetInterface");
}
if(SL_RESULT_SUCCESS == result)
{
- result = SLPlayItf_SetPlayState(player, SL_PLAYSTATE_PLAYING);
+ result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
PRINTERR(result, "player->SetPlayState");
}
if(SL_RESULT_SUCCESS != result)
{
if(data->bufferQueueObject != NULL)
- SLObjectItf_Destroy(data->bufferQueueObject);
+ VCALL0(data->bufferQueueObject,Destroy)();
data->bufferQueueObject = NULL;
free(data->buffer);
diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c
index c79793c2..93e026e9 100644
--- a/Alc/backends/oss.c
+++ b/Alc/backends/oss.c
@@ -78,10 +78,10 @@ typedef struct ALCplaybackOSS {
int data_size;
volatile int killNow;
- althread_t thread;
+ althrd_t thread;
} ALCplaybackOSS;
-static ALuint ALCplaybackOSS_mixerProc(ALvoid *ptr);
+static int ALCplaybackOSS_mixerProc(void *ptr);
static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device);
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, Destruct)
@@ -95,11 +95,11 @@ static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock)
-static void ALCplaybackOSS_Delete(ALCplaybackOSS *self);
+DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS)
DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS);
-static ALuint ALCplaybackOSS_mixerProc(ALvoid *ptr)
+static int ALCplaybackOSS_mixerProc(void *ptr)
{
ALCplaybackOSS *self = (ALCplaybackOSS*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -107,7 +107,7 @@ static ALuint ALCplaybackOSS_mixerProc(ALvoid *ptr)
ssize_t wrote;
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
@@ -131,7 +131,7 @@ static ALuint ALCplaybackOSS_mixerProc(ALvoid *ptr)
break;
}
- Sleep(1);
+ al_nssleep(0, 1000000);
continue;
}
@@ -168,7 +168,7 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
return ALC_INVALID_VALUE;
}
- device->DeviceName = strdup(name);
+ al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
@@ -275,7 +275,8 @@ static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self)
self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
self->mix_data = calloc(1, self->data_size);
- if(!StartThread(&self->thread, ALCplaybackOSS_mixerProc, self))
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success)
{
free(self->mix_data);
self->mix_data = NULL;
@@ -287,14 +288,14 @@ static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self)
static void ALCplaybackOSS_stop(ALCplaybackOSS *self)
{
- if(!self->thread)
+ int res;
+
+ if(self->killNow)
return;
self->killNow = 1;
- StopThread(self->thread);
- self->thread = NULL;
+ althrd_join(self->thread, &res);
- self->killNow = 0;
if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
ERR("Error resetting device: %s\n", strerror(errno));
@@ -302,11 +303,6 @@ static void ALCplaybackOSS_stop(ALCplaybackOSS *self)
self->mix_data = NULL;
}
-static void ALCplaybackOSS_Delete(ALCplaybackOSS *self)
-{
- free(self);
-}
-
typedef struct ALCcaptureOSS {
DERIVE_FROM_TYPE(ALCbackend);
@@ -320,10 +316,10 @@ typedef struct ALCcaptureOSS {
int doCapture;
volatile int killNow;
- althread_t thread;
+ althrd_t thread;
} ALCcaptureOSS;
-static ALuint ALCcaptureOSS_recordProc(ALvoid *ptr);
+static int ALCcaptureOSS_recordProc(void *ptr);
static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device);
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, Destruct)
@@ -337,11 +333,11 @@ static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self);
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock)
-static void ALCcaptureOSS_Delete(ALCcaptureOSS *self);
+DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS)
DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS);
-static ALuint ALCcaptureOSS_recordProc(ALvoid *ptr)
+static int ALCcaptureOSS_recordProc(void *ptr)
{
ALCcaptureOSS *self = (ALCcaptureOSS*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -349,7 +345,7 @@ static ALuint ALCcaptureOSS_recordProc(ALvoid *ptr)
int amt;
SetRTPriority();
- SetThreadName("alsoft-record");
+ althrd_setname(althrd_current(), "alsoft-record");
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
@@ -366,7 +362,7 @@ static ALuint ALCcaptureOSS_recordProc(ALvoid *ptr)
}
if(amt == 0)
{
- Sleep(1);
+ al_nssleep(0, 1000000);
continue;
}
if(self->doCapture)
@@ -488,7 +484,8 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
self->data_size = info.fragsize;
self->read_data = calloc(1, self->data_size);
- if(!StartThread(&self->thread, ALCcaptureOSS_recordProc, self))
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success)
{
device->ExtraData = NULL;
close(self->fd);
@@ -496,16 +493,17 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
return ALC_OUT_OF_MEMORY;
}
- device->DeviceName = strdup(name);
+ al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCcaptureOSS_close(ALCcaptureOSS *self)
{
+ int res;
+
self->killNow = 1;
- StopThread(self->thread);
- self->killNow = 0;
+ althrd_join(self->thread, &res);
close(self->fd);
self->fd = -1;
@@ -539,12 +537,6 @@ static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self)
return RingBufferSize(self->ring);
}
-void ALCcaptureOSS_Delete(ALCcaptureOSS *self)
-{
- free(self);
-}
-
-
typedef struct ALCossBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
@@ -615,8 +607,9 @@ ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self
{
ALCplaybackOSS *backend;
- backend = calloc(1, sizeof(*backend));
+ backend = ALCplaybackOSS_New(sizeof(*backend));
if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
ALCplaybackOSS_Construct(backend, device);
@@ -626,8 +619,9 @@ ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self
{
ALCcaptureOSS *backend;
- backend = calloc(1, sizeof(*backend));
+ backend = ALCcaptureOSS_New(sizeof(*backend));
if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
ALCcaptureOSS_Construct(backend, device);
diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c
index 162788fc..0bb6372c 100644
--- a/Alc/backends/portaudio.c
+++ b/Alc/backends/portaudio.c
@@ -212,7 +212,7 @@ retry_open:
}
device->ExtraData = data;
- device->DeviceName = strdup(deviceName);
+ al_string_copy_cstr(&device->DeviceName, deviceName);
return ALC_NO_ERROR;
}
@@ -354,7 +354,7 @@ static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
goto error;
}
- device->DeviceName = strdup(deviceName);
+ al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c
index e2ae52ae..58252240 100644
--- a/Alc/backends/pulseaudio.c
+++ b/Alc/backends/pulseaudio.c
@@ -306,9 +306,6 @@ static ALCboolean pulse_load(void)
static pa_context_flags_t pulse_ctx_flags;
static pa_proplist *prop_filter;
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
/* PulseAudio Event Callbacks */
static void context_state_callback(pa_context *context, void *pdata)
@@ -458,20 +455,33 @@ static void pulse_close(pa_threaded_mainloop *loop, pa_context *context,
typedef struct {
- char *name;
- char *device_name;
+ al_string name;
+ al_string device_name;
} DevMap;
+DECL_VECTOR(DevMap)
+
+static vector_DevMap PlaybackDevices;
+static vector_DevMap CaptureDevices;
+
+static void clear_devlist(vector_DevMap *list)
+{
+ DevMap *iter, *end;
-static DevMap *allDevNameMap;
-static ALuint numDevNames;
-static DevMap *allCaptureDevNameMap;
-static ALuint numCaptureDevNames;
+ iter = VECTOR_ITER_BEGIN(*list);
+ end = VECTOR_ITER_END(*list);
+ for(;iter != end;iter++)
+ {
+ AL_STRING_DEINIT(iter->name);
+ AL_STRING_DEINIT(iter->device_name);
+ }
+ VECTOR_RESIZE(*list, 0);
+}
typedef struct ALCpulsePlayback {
DERIVE_FROM_TYPE(ALCbackend);
- char *device_name;
+ al_string device_name;
pa_buffer_attr attr;
pa_sample_spec spec;
@@ -482,9 +492,8 @@ typedef struct ALCpulsePlayback {
pa_context *context;
volatile ALboolean killNow;
- althread_t thread;
+ althrd_t thread;
} ALCpulsePlayback;
-DECLARE_ALCBACKEND_VTABLE(ALCpulsePlayback);
static void ALCpulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
static void ALCpulsePlayback_probeDevices(void);
@@ -499,10 +508,10 @@ static pa_stream *ALCpulsePlayback_connectStream(const char *device_name, pa_thr
pa_context *context, pa_stream_flags_t flags,
pa_buffer_attr *attr, pa_sample_spec *spec,
pa_channel_map *chanmap);
-static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr);
+static int ALCpulsePlayback_mixerProc(void *ptr);
static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCpulsePlayback, ALCbackend, void, Destruct)
+static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self);
static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name);
static void ALCpulsePlayback_close(ALCpulsePlayback *self);
static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self);
@@ -510,22 +519,34 @@ static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self);
static void ALCpulsePlayback_stop(ALCpulsePlayback *self);
static DECLARE_FORWARD2(ALCpulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
static DECLARE_FORWARD(ALCpulsePlayback, ALCbackend, ALCuint, availableSamples)
+static ALint64 ALCpulsePlayback_getLatency(ALCpulsePlayback *self);
static void ALCpulsePlayback_lock(ALCpulsePlayback *self);
static void ALCpulsePlayback_unlock(ALCpulsePlayback *self);
+DECLARE_DEFAULT_ALLOCATORS(ALCpulsePlayback)
+
+DEFINE_ALCBACKEND_VTABLE(ALCpulsePlayback);
static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCpulsePlayback, ALCbackend, self);
+
+ AL_STRING_INIT(self->device_name);
+}
+
+static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self)
+{
+ AL_STRING_DEINIT(self->device_name);
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
{
pa_threaded_mainloop *loop = pdata;
- void *temp;
- ALuint i;
+ const DevMap *iter, *end;
+ DevMap entry;
if(eol)
{
@@ -533,29 +554,31 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p
return;
}
- for(i = 0;i < numDevNames;i++)
+ iter = VECTOR_ITER_BEGIN(PlaybackDevices);
+ end = VECTOR_ITER_END(PlaybackDevices);
+ for(;iter != end;iter++)
{
- if(strcmp(info->name, allDevNameMap[i].device_name) == 0)
+ if(al_string_cmp_cstr(iter->device_name, info->name) == 0)
return;
}
TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
- temp = realloc(allDevNameMap, (numDevNames+1) * sizeof(*allDevNameMap));
- if(temp)
- {
- allDevNameMap = temp;
- allDevNameMap[numDevNames].name = strdup(info->description);
- allDevNameMap[numDevNames].device_name = strdup(info->name);
- numDevNames++;
- }
+ AL_STRING_INIT(entry.name);
+ AL_STRING_INIT(entry.device_name);
+
+ al_string_copy_cstr(&entry.name, info->description);
+ al_string_copy_cstr(&entry.device_name, info->name);
+
+ VECTOR_PUSH_BACK(PlaybackDevices, entry);
}
static void ALCpulsePlayback_probeDevices(void)
{
pa_threaded_mainloop *loop;
- allDevNameMap = malloc(sizeof(DevMap) * 1);
+ clear_devlist(&PlaybackDevices);
+
if((loop=pa_threaded_mainloop_new()) &&
pa_threaded_mainloop_start(loop) >= 0)
{
@@ -697,8 +720,7 @@ static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const
return;
}
- free(device->DeviceName);
- device->DeviceName = strdup(info->description);
+ al_string_copy_cstr(&device->DeviceName, info->description);
}
@@ -706,10 +728,9 @@ static void ALCpulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata)
{
ALCpulsePlayback *self = pdata;
- free(self->device_name);
- self->device_name = strdup(pa_stream_get_device_name(stream));
+ al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(stream));
- TRACE("Stream moved to %s\n", self->device_name);
+ TRACE("Stream moved to %s\n", al_string_get_cstr(self->device_name));
}
@@ -754,7 +775,7 @@ static pa_stream *ALCpulsePlayback_connectStream(const char *device_name,
}
-static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr)
+static int ALCpulsePlayback_mixerProc(void *ptr)
{
ALCpulsePlayback *self = ptr;
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
@@ -764,7 +785,7 @@ static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr)
ssize_t len;
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
pa_threaded_mainloop_lock(self->loop);
frame_size = pa_frame_size(&self->spec);
@@ -786,7 +807,7 @@ static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr)
if(o) pa_operation_unref(o);
}
pa_threaded_mainloop_unlock(self->loop);
- Sleep(1);
+ al_nssleep(0, 1000000);
pa_threaded_mainloop_lock(self->loop);
continue;
}
@@ -828,20 +849,22 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
if(name)
{
- ALuint i;
+ const DevMap *iter, *end;
- if(!allDevNameMap)
+ if(VECTOR_SIZE(PlaybackDevices) == 0)
ALCpulsePlayback_probeDevices();
- for(i = 0;i < numDevNames;i++)
+ iter = VECTOR_ITER_BEGIN(PlaybackDevices);
+ end = VECTOR_ITER_END(PlaybackDevices);
+ for(;iter != end;iter++)
{
- if(strcmp(name, allDevNameMap[i].name) == 0)
+ if(al_string_cmp_cstr(iter->name, name) == 0)
{
- pulse_name = allDevNameMap[i].device_name;
+ pulse_name = al_string_get_cstr(iter->device_name);
break;
}
}
- if(i == numDevNames)
+ if(iter == end)
return ALC_INVALID_VALUE;
}
@@ -859,6 +882,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
spec.rate = 44100;
spec.channels = 2;
+ TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
self->stream = ALCpulsePlayback_connectStream(pulse_name, self->loop, self->context,
flags, NULL, &spec, NULL);
if(!self->stream)
@@ -871,8 +895,9 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
}
pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self);
- self->device_name = strdup(pa_stream_get_device_name(self->stream));
- o = pa_context_get_sink_info_by_name(self->context, self->device_name,
+ al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
+ o = pa_context_get_sink_info_by_name(self->context,
+ al_string_get_cstr(self->device_name),
ALCpulsePlayback_sinkNameCallback, self);
wait_for_operation(o, self->loop);
@@ -888,16 +913,15 @@ static void ALCpulsePlayback_close(ALCpulsePlayback *self)
self->context = NULL;
self->stream = NULL;
- free(self->device_name);
- self->device_name = NULL;
+ al_string_clear(&self->device_name);
}
static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
pa_stream_flags_t flags = 0;
+ const char *mapname = NULL;
pa_channel_map chanmap;
- const char *mapname;
ALuint len;
pa_threaded_mainloop_lock(self->loop);
@@ -917,7 +941,8 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
{
pa_operation *o;
- o = pa_context_get_sink_info_by_name(self->context, self->device_name,
+ o = pa_context_get_sink_info_by_name(self->context,
+ al_string_get_cstr(self->device_name),
ALCpulsePlayback_sinkInfoCallback, self);
wait_for_operation(o, self->loop);
}
@@ -964,7 +989,6 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
return ALC_FALSE;
}
- mapname = "(invalid)";
switch(device->FmtChans)
{
case DevFmtMono:
@@ -1003,9 +1027,9 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
self->attr.tlength = self->attr.minreq * maxu(device->NumUpdates, 2);
self->attr.maxlength = -1;
- self->stream = ALCpulsePlayback_connectStream(self->device_name, self->loop,
- self->context, flags, &self->attr,
- &self->spec, &chanmap);
+ self->stream = ALCpulsePlayback_connectStream(al_string_get_cstr(self->device_name),
+ self->loop, self->context, flags,
+ &self->attr, &self->spec, &chanmap);
if(!self->stream)
{
pa_threaded_mainloop_unlock(self->loop);
@@ -1054,7 +1078,8 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self)
{
- if(!StartThread(&self->thread, ALCpulsePlayback_mixerProc, self))
+ self->killNow = AL_FALSE;
+ if(althrd_create(&self->thread, ALCpulsePlayback_mixerProc, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
}
@@ -1062,17 +1087,13 @@ static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self)
static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
{
pa_operation *o;
+ int res;
if(!self->stream)
return;
self->killNow = AL_TRUE;
- if(self->thread)
- {
- StopThread(self->thread);
- self->thread = NULL;
- }
- self->killNow = AL_FALSE;
+ althrd_join(self->thread, &res);
pa_threaded_mainloop_lock(self->loop);
@@ -1083,25 +1104,19 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
}
-static void ALCpulsePlayback_lock(ALCpulsePlayback *self)
-{
- pa_threaded_mainloop_lock(self->loop);
-}
-
-static void ALCpulsePlayback_unlock(ALCpulsePlayback *self)
-{
- pa_threaded_mainloop_unlock(self->loop);
-}
-
-
static ALint64 ALCpulsePlayback_getLatency(ALCpulsePlayback *self)
{
pa_usec_t latency = 0;
- int neg;
+ int neg, err;
- if(pa_stream_get_latency(self->stream, &latency, &neg) != 0)
+ if((err=pa_stream_get_latency(self->stream, &latency, &neg)) != 0)
{
- ERR("Failed to get stream latency!\n");
+ /* FIXME: if err = -PA_ERR_NODATA, it means we were called too soon
+ * after starting the stream and no timing info has been received from
+ * the server yet. Should we wait, possibly stalling the app, or give a
+ * dummy value? Either way, it shouldn't be 0. */
+ if(err != -PA_ERR_NODATA)
+ ERR("Failed to get stream latency: 0x%x\n", err);
return 0;
}
@@ -1110,18 +1125,21 @@ static ALint64 ALCpulsePlayback_getLatency(ALCpulsePlayback *self)
}
-static void ALCpulsePlayback_Delete(ALCpulsePlayback *self)
+static void ALCpulsePlayback_lock(ALCpulsePlayback *self)
{
- free(self);
+ pa_threaded_mainloop_lock(self->loop);
}
-DEFINE_ALCBACKEND_VTABLE(ALCpulsePlayback);
+static void ALCpulsePlayback_unlock(ALCpulsePlayback *self)
+{
+ pa_threaded_mainloop_unlock(self->loop);
+}
typedef struct ALCpulseCapture {
DERIVE_FROM_TYPE(ALCbackend);
- char *device_name;
+ al_string device_name;
const void *cap_store;
size_t cap_len;
@@ -1137,7 +1155,6 @@ typedef struct ALCpulseCapture {
pa_stream *stream;
pa_context *context;
} ALCpulseCapture;
-DECLARE_ALCBACKEND_VTABLE(ALCpulseCapture);
static void ALCpulseCapture_deviceCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata);
static void ALCpulseCapture_probeDevices(void);
@@ -1152,7 +1169,7 @@ static pa_stream *ALCpulseCapture_connectStream(const char *device_name,
pa_sample_spec *spec, pa_channel_map *chanmap);
static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCpulseCapture, ALCbackend, void, Destruct)
+static void ALCpulseCapture_Destruct(ALCpulseCapture *self);
static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name);
static void ALCpulseCapture_close(ALCpulseCapture *self);
static DECLARE_FORWARD(ALCpulseCapture, ALCbackend, ALCboolean, reset)
@@ -1160,22 +1177,34 @@ static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self);
static void ALCpulseCapture_stop(ALCpulseCapture *self);
static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self);
+static ALint64 ALCpulseCapture_getLatency(ALCpulseCapture *self);
static void ALCpulseCapture_lock(ALCpulseCapture *self);
static void ALCpulseCapture_unlock(ALCpulseCapture *self);
+DECLARE_DEFAULT_ALLOCATORS(ALCpulseCapture)
+
+DEFINE_ALCBACKEND_VTABLE(ALCpulseCapture);
static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCpulseCapture, ALCbackend, self);
+
+ AL_STRING_INIT(self->device_name);
+}
+
+static void ALCpulseCapture_Destruct(ALCpulseCapture *self)
+{
+ AL_STRING_DEINIT(self->device_name);
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata)
{
pa_threaded_mainloop *loop = pdata;
- void *temp;
- ALuint i;
+ const DevMap *iter, *end;
+ DevMap entry;
if(eol)
{
@@ -1183,29 +1212,31 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa
return;
}
- for(i = 0;i < numCaptureDevNames;i++)
+ iter = VECTOR_ITER_BEGIN(CaptureDevices);
+ end = VECTOR_ITER_END(CaptureDevices);
+ for(;iter != end;iter++)
{
- if(strcmp(info->name, allCaptureDevNameMap[i].device_name) == 0)
+ if(al_string_cmp_cstr(iter->device_name, info->name) == 0)
return;
}
TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
- temp = realloc(allCaptureDevNameMap, (numCaptureDevNames+1) * sizeof(*allCaptureDevNameMap));
- if(temp)
- {
- allCaptureDevNameMap = temp;
- allCaptureDevNameMap[numCaptureDevNames].name = strdup(info->description);
- allCaptureDevNameMap[numCaptureDevNames].device_name = strdup(info->name);
- numCaptureDevNames++;
- }
+ AL_STRING_INIT(entry.name);
+ AL_STRING_INIT(entry.device_name);
+
+ al_string_copy_cstr(&entry.name, info->description);
+ al_string_copy_cstr(&entry.device_name, info->name);
+
+ VECTOR_PUSH_BACK(CaptureDevices, entry);
}
static void ALCpulseCapture_probeDevices(void)
{
pa_threaded_mainloop *loop;
- allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);
+ clear_devlist(&CaptureDevices);
+
if((loop=pa_threaded_mainloop_new()) &&
pa_threaded_mainloop_start(loop) >= 0)
{
@@ -1288,8 +1319,7 @@ static void ALCpulseCapture_sourceNameCallback(pa_context *UNUSED(context), cons
return;
}
- free(device->DeviceName);
- device->DeviceName = strdup(info->description);
+ al_string_copy_cstr(&device->DeviceName, info->description);
}
@@ -1297,10 +1327,9 @@ static void ALCpulseCapture_streamMovedCallback(pa_stream *stream, void *pdata)
{
ALCpulseCapture *self = pdata;
- free(self->device_name);
- self->device_name = strdup(pa_stream_get_device_name(stream));
+ al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(stream));
- TRACE("Stream moved to %s\n", self->device_name);
+ TRACE("Stream moved to %s\n", al_string_get_cstr(self->device_name));
}
@@ -1356,20 +1385,22 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
if(name)
{
- ALuint i;
+ const DevMap *iter, *end;
- if(!allCaptureDevNameMap)
+ if(VECTOR_SIZE(CaptureDevices) == 0)
ALCpulseCapture_probeDevices();
- for(i = 0;i < numCaptureDevNames;i++)
+ iter = VECTOR_ITER_BEGIN(CaptureDevices);
+ end = VECTOR_ITER_END(CaptureDevices);
+ for(;iter != end;iter++)
{
- if(strcmp(name, allCaptureDevNameMap[i].name) == 0)
+ if(al_string_cmp_cstr(iter->name, name) == 0)
{
- pulse_name = allCaptureDevNameMap[i].device_name;
+ pulse_name = al_string_get_cstr(iter->device_name);
break;
}
}
- if(i == numCaptureDevNames)
+ if(iter == end)
return ALC_INVALID_VALUE;
}
@@ -1431,6 +1462,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
if(!GetConfigValueBool("pulse", "allow-moves", 0))
flags |= PA_STREAM_DONT_MOVE;
+ TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
self->stream = ALCpulseCapture_connectStream(pulse_name, self->loop, self->context,
flags, &self->attr, &self->spec,
&chanmap);
@@ -1442,8 +1474,9 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
pa_stream_set_moved_callback(self->stream, ALCpulseCapture_streamMovedCallback, self);
pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self);
- self->device_name = strdup(pa_stream_get_device_name(self->stream));
- o = pa_context_get_source_info_by_name(self->context, self->device_name,
+ al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
+ o = pa_context_get_source_info_by_name(self->context,
+ al_string_get_cstr(self->device_name),
ALCpulseCapture_sourceNameCallback, self);
wait_for_operation(o, self->loop);
@@ -1466,8 +1499,7 @@ static void ALCpulseCapture_close(ALCpulseCapture *self)
self->context = NULL;
self->stream = NULL;
- free(self->device_name);
- self->device_name = NULL;
+ al_string_clear(&self->device_name);
}
static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self)
@@ -1562,17 +1594,6 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self)
}
-static void ALCpulseCapture_lock(ALCpulseCapture *self)
-{
- pa_threaded_mainloop_lock(self->loop);
-}
-
-static void ALCpulseCapture_unlock(ALCpulseCapture *self)
-{
- pa_threaded_mainloop_unlock(self->loop);
-}
-
-
static ALint64 ALCpulseCapture_getLatency(ALCpulseCapture *self)
{
pa_usec_t latency = 0;
@@ -1589,23 +1610,43 @@ static ALint64 ALCpulseCapture_getLatency(ALCpulseCapture *self)
}
-static void ALCpulseCapture_Delete(ALCpulseCapture *self)
+static void ALCpulseCapture_lock(ALCpulseCapture *self)
{
- free(self);
+ pa_threaded_mainloop_lock(self->loop);
+}
+
+static void ALCpulseCapture_unlock(ALCpulseCapture *self)
+{
+ pa_threaded_mainloop_unlock(self->loop);
}
-DEFINE_ALCBACKEND_VTABLE(ALCpulseCapture);
+static inline void AppendAllDevicesList2(const DevMap *entry)
+{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
+static inline void AppendCaptureDeviceList2(const DevMap *entry)
+{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
typedef struct ALCpulseBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCpulseBackendFactory;
#define ALCPULSEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCpulseBackendFactory, ALCbackendFactory) } }
+static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory *self);
+static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory *self);
+static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory *self, ALCbackend_Type type);
+static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory);
+
+
static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(self))
{
ALCboolean ret = ALC_FALSE;
+ VECTOR_INIT(PlaybackDevices);
+ VECTOR_INIT(CaptureDevices);
+
if(pulse_load())
{
pa_threaded_mainloop *loop;
@@ -1648,25 +1689,11 @@ static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(sel
static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self))
{
- ALuint i;
-
- for(i = 0;i < numDevNames;++i)
- {
- free(allDevNameMap[i].name);
- free(allDevNameMap[i].device_name);
- }
- free(allDevNameMap);
- allDevNameMap = NULL;
- numDevNames = 0;
+ clear_devlist(&PlaybackDevices);
+ VECTOR_DEINIT(PlaybackDevices);
- for(i = 0;i < numCaptureDevNames;++i)
- {
- free(allCaptureDevNameMap[i].name);
- free(allCaptureDevNameMap[i].device_name);
- }
- free(allCaptureDevNameMap);
- allCaptureDevNameMap = NULL;
- numCaptureDevNames = 0;
+ clear_devlist(&CaptureDevices);
+ VECTOR_DEINIT(CaptureDevices);
if(prop_filter)
pa_proplist_free(prop_filter);
@@ -1684,40 +1711,16 @@ static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UN
static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type)
{
- ALuint i;
-
switch(type)
{
case ALL_DEVICE_PROBE:
- for(i = 0;i < numDevNames;++i)
- {
- free(allDevNameMap[i].name);
- free(allDevNameMap[i].device_name);
- }
- free(allDevNameMap);
- allDevNameMap = NULL;
- numDevNames = 0;
-
ALCpulsePlayback_probeDevices();
-
- for(i = 0;i < numDevNames;i++)
- AppendAllDevicesList(allDevNameMap[i].name);
+ VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
- for(i = 0;i < numCaptureDevNames;++i)
- {
- free(allCaptureDevNameMap[i].name);
- free(allCaptureDevNameMap[i].device_name);
- }
- free(allCaptureDevNameMap);
- allCaptureDevNameMap = NULL;
- numCaptureDevNames = 0;
-
ALCpulseCapture_probeDevices();
-
- for(i = 0;i < numCaptureDevNames;i++)
- AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
+ VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
break;
}
}
@@ -1728,8 +1731,9 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory*
{
ALCpulsePlayback *backend;
- backend = calloc(1, sizeof(*backend));
+ backend = ALCpulsePlayback_New(sizeof(*backend));
if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
ALCpulsePlayback_Construct(backend, device);
@@ -1739,8 +1743,9 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory*
{
ALCpulseCapture *backend;
- backend = calloc(1, sizeof(*backend));
+ backend = ALCpulseCapture_New(sizeof(*backend));
if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
ALCpulseCapture_Construct(backend, device);
@@ -1750,8 +1755,6 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory*
return NULL;
}
-DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory);
-
#else /* PA_API_VERSION == 12 */
diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c
index c9762f85..9258e4e5 100644
--- a/Alc/backends/qsa.c
+++ b/Alc/backends/qsa.c
@@ -34,8 +34,7 @@
#include "threads.h"
-typedef struct
-{
+typedef struct {
snd_pcm_t* pcmHandle;
int audio_fd;
@@ -46,27 +45,24 @@ typedef struct
ALsizei size;
volatile int killNow;
- althread_t thread;
+ althrd_t thread;
} qsa_data;
-typedef struct
-{
+typedef struct {
ALCchar* name;
int card;
int dev;
} DevMap;
-static const ALCchar qsaDevice[]="QSA Default";
+static const ALCchar qsaDevice[] = "QSA Default";
static DevMap* allDevNameMap;
static ALuint numDevNames;
static DevMap* allCaptureDevNameMap;
static ALuint numCaptureDevNames;
-static const struct
-{
+static const struct {
int32_t format;
-} formatlist[]=
-{
+} formatlist[] = {
{SND_PCM_SFMT_FLOAT_LE},
{SND_PCM_SFMT_S32_LE},
{SND_PCM_SFMT_U32_LE},
@@ -77,11 +73,9 @@ static const struct
{0},
};
-static const struct
-{
+static const struct {
int32_t rate;
-} ratelist[]=
-{
+} ratelist[] = {
{192000},
{176400},
{96000},
@@ -98,11 +92,9 @@ static const struct
{0},
};
-static const struct
-{
+static const struct {
int32_t channels;
-} channellist[]=
-{
+} channellist[] = {
{8},
{7},
{6},
@@ -112,7 +104,7 @@ static const struct
{0},
};
-static DevMap* deviceList(int type, ALuint* count)
+static DevMap *deviceList(int type, ALuint *count)
{
snd_ctl_t* handle;
snd_pcm_info_t pcminfo;
@@ -178,7 +170,7 @@ static DevMap* deviceList(int type, ALuint* count)
}
-FORCE_ALIGN static ALuint qsa_proc_playback(ALvoid* ptr)
+FORCE_ALIGN static int qsa_proc_playback(void* ptr)
{
ALCdevice* device=(ALCdevice*)ptr;
qsa_data* data=(qsa_data*)device->ExtraData;
@@ -191,7 +183,7 @@ FORCE_ALIGN static ALuint qsa_proc_playback(ALvoid* ptr)
struct timeval timeout;
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
/* Increase default 10 priority to 11 to avoid jerky sound */
SchedGet(0, 0, &param);
@@ -343,8 +335,8 @@ static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
return ALC_INVALID_DEVICE;
}
- device->DeviceName=strdup(deviceName);
- device->ExtraData=data;
+ al_string_copy_cstr(&device->DeviceName, deviceName);
+ device->ExtraData = data;
return ALC_NO_ERROR;
}
@@ -616,7 +608,8 @@ static ALCboolean qsa_start_playback(ALCdevice* device)
{
qsa_data *data = (qsa_data*)device->ExtraData;
- if(!StartThread(&data->thread, qsa_proc_playback, device))
+ data->killNow = 0;
+ if(althrd_create(&data->thread, qsa_proc_playback, device) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
@@ -624,15 +617,14 @@ static ALCboolean qsa_start_playback(ALCdevice* device)
static void qsa_stop_playback(ALCdevice* device)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ qsa_data *data = (qsa_data*)device->ExtraData;
+ int res;
- if (data->thread)
- {
- data->killNow=1;
- StopThread(data->thread);
- data->thread=NULL;
- }
- data->killNow=0;
+ if(data->killNow)
+ return;
+
+ data->killNow = 1;
+ althrd_join(data->thread, &res);
}
/***********/
@@ -711,8 +703,8 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
return ALC_INVALID_DEVICE;
}
- device->DeviceName=strdup(deviceName);
- device->ExtraData=data;
+ al_string_copy_cstr(&device->DeviceName, deviceName);
+ device->ExtraData = data;
switch (device->FmtType)
{
diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c
index 80aebfd1..7152b2d6 100644
--- a/Alc/backends/sndio.c
+++ b/Alc/backends/sndio.c
@@ -47,11 +47,11 @@ typedef struct {
ALsizei data_size;
volatile int killNow;
- althread_t thread;
+ althrd_t thread;
} sndio_data;
-static ALuint sndio_proc(ALvoid *ptr)
+static int sndio_proc(void *ptr)
{
ALCdevice *device = ptr;
sndio_data *data = device->ExtraData;
@@ -59,7 +59,7 @@ static ALuint sndio_proc(ALvoid *ptr)
size_t wrote;
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
@@ -111,7 +111,7 @@ static ALCenum sndio_open_playback(ALCdevice *device, const ALCchar *deviceName)
return ALC_INVALID_VALUE;
}
- device->DeviceName = strdup(deviceName);
+ al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
@@ -224,7 +224,8 @@ static ALCboolean sndio_start_playback(ALCdevice *device)
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->mix_data = calloc(1, data->data_size);
- if(!StartThread(&data->thread, sndio_proc, device))
+ data->killNow = 0;
+ if(althrd_create(&data->thread, sndio_proc, device) != althrd_success)
{
sio_stop(data->sndHandle);
free(data->mix_data);
@@ -238,15 +239,14 @@ static ALCboolean sndio_start_playback(ALCdevice *device)
static void sndio_stop_playback(ALCdevice *device)
{
sndio_data *data = device->ExtraData;
+ int res;
- if(!data->thread)
+ if(data->killNow)
return;
data->killNow = 1;
- StopThread(data->thread);
- data->thread = NULL;
+ althrd_join(data->thread, &res);
- data->killNow = 0;
if(!sio_stop(data->sndHandle))
ERR("Error stopping device\n");
diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c
index 700131c8..20d861d2 100644
--- a/Alc/backends/solaris.c
+++ b/Alc/backends/solaris.c
@@ -50,11 +50,11 @@ typedef struct {
int data_size;
volatile int killNow;
- althread_t thread;
+ althrd_t thread;
} solaris_data;
-static ALuint SolarisProc(ALvoid *ptr)
+static int SolarisProc(void *ptr)
{
ALCdevice *Device = (ALCdevice*)ptr;
solaris_data *data = (solaris_data*)Device->ExtraData;
@@ -62,7 +62,7 @@ static ALuint SolarisProc(ALvoid *ptr)
int wrote;
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
@@ -86,7 +86,7 @@ static ALuint SolarisProc(ALvoid *ptr)
break;
}
- Sleep(1);
+ al_nssleep(0, 1000000);
continue;
}
@@ -119,7 +119,7 @@ static ALCenum solaris_open_playback(ALCdevice *device, const ALCchar *deviceNam
return ALC_INVALID_VALUE;
}
- device->DeviceName = strdup(deviceName);
+ al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
}
@@ -211,7 +211,8 @@ static ALCboolean solaris_start_playback(ALCdevice *device)
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->mix_data = calloc(1, data->data_size);
- if(!StartThread(&data->thread, SolarisProc, device))
+ data->killNow = 0;
+ if(althrd_create(&data->thread, SolarisProc, device) != althrd_success)
{
free(data->mix_data);
data->mix_data = NULL;
@@ -224,15 +225,14 @@ static ALCboolean solaris_start_playback(ALCdevice *device)
static void solaris_stop_playback(ALCdevice *device)
{
solaris_data *data = (solaris_data*)device->ExtraData;
+ int res;
- if(!data->thread)
+ if(data->killNow)
return;
data->killNow = 1;
- StopThread(data->thread);
- data->thread = NULL;
+ althrd_join(data->thread, &res);
- data->killNow = 0;
if(ioctl(data->fd, AUDIO_DRAIN) < 0)
ERR("Error draining device: %s\n", strerror(errno));
diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c
index 2fafc4b9..421ca5d7 100644
--- a/Alc/backends/wave.c
+++ b/Alc/backends/wave.c
@@ -42,7 +42,7 @@ typedef struct {
ALuint size;
volatile int killNow;
- althread_t thread;
+ althrd_t thread;
} wave_data;
@@ -85,49 +85,55 @@ static void fwrite32le(ALuint val, FILE *f)
}
-static ALuint WaveProc(ALvoid *ptr)
+static int WaveProc(void *ptr)
{
- ALCdevice *Device = (ALCdevice*)ptr;
- wave_data *data = (wave_data*)Device->ExtraData;
+ ALCdevice *device = (ALCdevice*)ptr;
+ wave_data *data = (wave_data*)device->ExtraData;
+ struct timespec now, start;
+ ALint64 avail, done;
ALuint frameSize;
- ALuint now, start;
- ALuint64 avail, done;
size_t fs;
- const ALuint restTime = (ALuint64)Device->UpdateSize * 1000 /
- Device->Frequency / 2;
+ const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 /
+ device->Frequency / 2);
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
- frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
+ frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
done = 0;
- start = timeGetTime();
- while(!data->killNow && Device->Connected)
+ if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC)
{
- now = timeGetTime();
-
- avail = (ALuint64)(now-start) * Device->Frequency / 1000;
- if(avail < done)
+ ERR("Failed to get starting time\n");
+ return 1;
+ }
+ while(!data->killNow && device->Connected)
+ {
+ if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
{
- /* Timer wrapped (50 days???). Add the remainder of the cycle to
- * the available count and reset the number of samples done */
- avail += ((ALuint64)1<<32)*Device->Frequency/1000 - done;
- done = 0;
+ ERR("Failed to get current time\n");
+ return 1;
}
- if(avail-done < Device->UpdateSize)
+
+ avail = (now.tv_sec - start.tv_sec) * device->Frequency;
+ avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000;
+ if(avail < done)
{
- Sleep(restTime);
- continue;
+ /* Oops, time skipped backwards. Reset the number of samples done
+ * with one update available since we (likely) just came back from
+ * sleeping. */
+ done = avail - device->UpdateSize;
}
- while(avail-done >= Device->UpdateSize)
+ if(avail-done < device->UpdateSize)
+ al_nssleep(0, restTime);
+ else while(avail-done >= device->UpdateSize)
{
- aluMixData(Device, data->buffer, Device->UpdateSize);
- done += Device->UpdateSize;
+ aluMixData(device, data->buffer, device->UpdateSize);
+ done += device->UpdateSize;
if(!IS_LITTLE_ENDIAN)
{
- ALuint bytesize = BytesFromDevFmt(Device->FmtType);
+ ALuint bytesize = BytesFromDevFmt(device->FmtType);
ALubyte *bytes = data->buffer;
ALuint i;
@@ -149,16 +155,16 @@ static ALuint WaveProc(ALvoid *ptr)
}
else
{
- fs = fwrite(data->buffer, frameSize, Device->UpdateSize,
+ fs = fwrite(data->buffer, frameSize, device->UpdateSize,
data->f);
(void)fs;
}
if(ferror(data->f))
{
ERR("Error writing to file\n");
- ALCdevice_Lock(Device);
- aluHandleDisconnect(Device);
- ALCdevice_Unlock(Device);
+ ALCdevice_Lock(device);
+ aluHandleDisconnect(device);
+ ALCdevice_Unlock(device);
break;
}
}
@@ -183,7 +189,7 @@ static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
data = (wave_data*)calloc(1, sizeof(wave_data));
- data->f = fopen(fname, "wb");
+ data->f = al_fopen(fname, "wb");
if(!data->f)
{
free(data);
@@ -191,7 +197,7 @@ static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
return ALC_INVALID_VALUE;
}
- device->DeviceName = strdup(deviceName);
+ al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
}
@@ -291,7 +297,8 @@ static ALCboolean wave_start_playback(ALCdevice *device)
return ALC_FALSE;
}
- if(!StartThread(&data->thread, WaveProc, device))
+ data->killNow = 0;
+ if(althrd_create(&data->thread, WaveProc, device) != althrd_success)
{
free(data->buffer);
data->buffer = NULL;
@@ -306,15 +313,13 @@ static void wave_stop_playback(ALCdevice *device)
wave_data *data = (wave_data*)device->ExtraData;
ALuint dataLen;
long size;
+ int res;
- if(!data->thread)
+ if(data->killNow)
return;
data->killNow = 1;
- StopThread(data->thread);
- data->thread = NULL;
-
- data->killNow = 0;
+ althrd_join(data->thread, &res);
free(data->buffer);
data->buffer = NULL;
diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c
index 7082a874..624af37a 100644
--- a/Alc/backends/winmm.c
+++ b/Alc/backends/winmm.c
@@ -39,10 +39,9 @@
typedef struct {
// MMSYSTEM Device
volatile ALboolean killNow;
- HANDLE WaveThreadEvent;
- HANDLE WaveThread;
- DWORD WaveThreadID;
- volatile LONG WaveBuffersCommitted;
+ althrd_t thread;
+
+ RefCount WaveBuffersCommitted;
WAVEHDR WaveBuffer[4];
union {
@@ -56,87 +55,106 @@ typedef struct {
} WinMMData;
-static ALCchar **PlaybackDeviceList;
-static ALuint NumPlaybackDevices;
-static ALCchar **CaptureDeviceList;
-static ALuint NumCaptureDevices;
+static vector_al_string PlaybackDevices;
+static vector_al_string CaptureDevices;
+
+static void clear_devlist(vector_al_string *list)
+{
+ al_string *iter, *end;
+
+ iter = VECTOR_ITER_BEGIN(*list);
+ end = VECTOR_ITER_END(*list);
+ for(;iter != end;iter++)
+ AL_STRING_DEINIT(*iter);
+ VECTOR_RESIZE(*list, 0);
+}
static void ProbePlaybackDevices(void)
{
+ al_string *iter, *end;
+ ALuint numdevs;
ALuint i;
- for(i = 0;i < NumPlaybackDevices;i++)
- free(PlaybackDeviceList[i]);
+ clear_devlist(&PlaybackDevices);
- NumPlaybackDevices = waveOutGetNumDevs();
- PlaybackDeviceList = realloc(PlaybackDeviceList, sizeof(ALCchar*) * NumPlaybackDevices);
- for(i = 0;i < NumPlaybackDevices;i++)
+ numdevs = waveOutGetNumDevs();
+ VECTOR_RESERVE(PlaybackDevices, numdevs);
+ for(i = 0;i < numdevs;i++)
{
- WAVEOUTCAPS WaveCaps;
+ WAVEOUTCAPSW WaveCaps;
+ al_string dname;
- PlaybackDeviceList[i] = NULL;
- if(waveOutGetDevCaps(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
+ AL_STRING_INIT(dname);
+ if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
{
- char name[1024];
- ALuint count, j;
-
- count = 0;
+ ALuint count = 0;
do {
- if(count == 0)
- snprintf(name, sizeof(name), "%s", WaveCaps.szPname);
- else
- snprintf(name, sizeof(name), "%s #%d", WaveCaps.szPname, count+1);
+ al_string_copy_wcstr(&dname, WaveCaps.szPname);
+ if(count != 0)
+ {
+ char str[64];
+ snprintf(str, sizeof(str), " #%d", count+1);
+ al_string_append_cstr(&dname, str);
+ }
count++;
- for(j = 0;j < i;j++)
+ iter = VECTOR_ITER_BEGIN(PlaybackDevices);
+ end = VECTOR_ITER_END(PlaybackDevices);
+ for(;iter != end;iter++)
{
- if(strcmp(name, PlaybackDeviceList[j]) == 0)
+ if(al_string_cmp(*iter, dname) == 0)
break;
}
- } while(j != i);
+ } while(iter != end);
- PlaybackDeviceList[i] = strdup(name);
+ TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
}
+ VECTOR_PUSH_BACK(PlaybackDevices, dname);
}
}
static void ProbeCaptureDevices(void)
{
+ al_string *iter, *end;
+ ALuint numdevs;
ALuint i;
- for(i = 0;i < NumCaptureDevices;i++)
- free(CaptureDeviceList[i]);
+ clear_devlist(&CaptureDevices);
- NumCaptureDevices = waveInGetNumDevs();
- CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices);
- for(i = 0;i < NumCaptureDevices;i++)
+ numdevs = waveInGetNumDevs();
+ VECTOR_RESERVE(CaptureDevices, numdevs);
+ for(i = 0;i < numdevs;i++)
{
- WAVEINCAPS WaveInCaps;
+ WAVEINCAPSW WaveCaps;
+ al_string dname;
- CaptureDeviceList[i] = NULL;
- if(waveInGetDevCaps(i, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
+ AL_STRING_INIT(dname);
+ if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
{
- char name[1024];
- ALuint count, j;
-
- count = 0;
+ ALuint count = 0;
do {
- if(count == 0)
- snprintf(name, sizeof(name), "%s", WaveInCaps.szPname);
- else
- snprintf(name, sizeof(name), "%s #%d", WaveInCaps.szPname, count+1);
+ al_string_copy_wcstr(&dname, WaveCaps.szPname);
+ if(count != 0)
+ {
+ char str[64];
+ snprintf(str, sizeof(str), " #%d", count+1);
+ al_string_append_cstr(&dname, str);
+ }
count++;
- for(j = 0;j < i;j++)
+ iter = VECTOR_ITER_BEGIN(CaptureDevices);
+ end = VECTOR_ITER_END(CaptureDevices);
+ for(;iter != end;iter++)
{
- if(strcmp(name, CaptureDeviceList[j]) == 0)
+ if(al_string_cmp(*iter, dname) == 0)
break;
}
- } while(j != i);
+ } while(iter != end);
- CaptureDeviceList[i] = strdup(name);
+ TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
}
+ VECTOR_PUSH_BACK(CaptureDevices, dname);
}
}
@@ -155,28 +173,19 @@ static void CALLBACK WaveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR in
if(msg != WOM_DONE)
return;
- InterlockedDecrement(&data->WaveBuffersCommitted);
- PostThreadMessage(data->WaveThreadID, msg, 0, param1);
+ DecrementRef(&data->WaveBuffersCommitted);
+ PostThreadMessage(data->thread, msg, 0, param1);
}
-/*
- PlaybackThreadProc
-
- Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its
- audio data.
-*/
-FORCE_ALIGN static DWORD WINAPI PlaybackThreadProc(LPVOID param)
+FORCE_ALIGN static int PlaybackThreadProc(void *arg)
{
- ALCdevice *Device = (ALCdevice*)param;
+ ALCdevice *Device = (ALCdevice*)arg;
WinMMData *data = Device->ExtraData;
- LPWAVEHDR WaveHdr;
- ALuint FrameSize;
+ WAVEHDR *WaveHdr;
MSG msg;
- FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
-
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
while(GetMessage(&msg, NULL, 0, 0))
{
@@ -185,24 +194,20 @@ FORCE_ALIGN static DWORD WINAPI PlaybackThreadProc(LPVOID param)
if(data->killNow)
{
- if(data->WaveBuffersCommitted == 0)
+ if(ReadRef(&data->WaveBuffersCommitted) == 0)
break;
continue;
}
- WaveHdr = ((LPWAVEHDR)msg.lParam);
- aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength/FrameSize);
+ WaveHdr = ((WAVEHDR*)msg.lParam);
+ aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength /
+ data->Format.nBlockAlign);
// Send buffer back to play more data
waveOutWrite(data->WaveHandle.Out, WaveHdr, sizeof(WAVEHDR));
- InterlockedIncrement(&data->WaveBuffersCommitted);
+ IncrementRef(&data->WaveBuffersCommitted);
}
- // Signal Wave Thread completed event
- if(data->WaveThreadEvent)
- SetEvent(data->WaveThreadEvent);
-
- ExitThread(0);
return 0;
}
@@ -220,26 +225,18 @@ static void CALLBACK WaveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR inst
if(msg != WIM_DATA)
return;
- InterlockedDecrement(&data->WaveBuffersCommitted);
- PostThreadMessage(data->WaveThreadID, msg, 0, param1);
+ DecrementRef(&data->WaveBuffersCommitted);
+ PostThreadMessage(data->thread, msg, 0, param1);
}
-/*
- CaptureThreadProc
-
- Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new
- audio data.
-*/
-static DWORD WINAPI CaptureThreadProc(LPVOID param)
+static int CaptureThreadProc(void *arg)
{
- ALCdevice *Device = (ALCdevice*)param;
+ ALCdevice *Device = (ALCdevice*)arg;
WinMMData *data = Device->ExtraData;
- LPWAVEHDR WaveHdr;
- ALuint FrameSize;
+ WAVEHDR *WaveHdr;
MSG msg;
- FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
- SetThreadName("alsoft-record");
+ althrd_setname(althrd_current(), "alsoft-record");
while(GetMessage(&msg, NULL, 0, 0))
{
@@ -250,19 +247,15 @@ static DWORD WINAPI CaptureThreadProc(LPVOID param)
if(data->killNow)
break;
- WaveHdr = ((LPWAVEHDR)msg.lParam);
- WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData, WaveHdr->dwBytesRecorded/FrameSize);
+ WaveHdr = ((WAVEHDR*)msg.lParam);
+ WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData,
+ WaveHdr->dwBytesRecorded/data->Format.nBlockAlign);
// Send buffer back to capture more data
waveInAddBuffer(data->WaveHandle.In, WaveHdr, sizeof(WAVEHDR));
- InterlockedIncrement(&data->WaveBuffersCommitted);
+ IncrementRef(&data->WaveBuffersCommitted);
}
- // Signal Wave Thread completed event
- if(data->WaveThreadEvent)
- SetEvent(data->WaveThreadEvent);
-
- ExitThread(0);
return 0;
}
@@ -270,24 +263,26 @@ static DWORD WINAPI CaptureThreadProc(LPVOID param)
static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName)
{
WinMMData *data = NULL;
- UINT DeviceID = 0;
+ const al_string *iter, *end;
+ UINT DeviceID;
MMRESULT res;
- ALuint i = 0;
- if(!PlaybackDeviceList)
+ if(VECTOR_SIZE(PlaybackDevices) == 0)
ProbePlaybackDevices();
// Find the Device ID matching the deviceName if valid
- for(i = 0;i < NumPlaybackDevices;i++)
+ iter = VECTOR_ITER_BEGIN(PlaybackDevices);
+ end = VECTOR_ITER_END(PlaybackDevices);
+ for(;iter != end;iter++)
{
- if(PlaybackDeviceList[i] &&
- (!deviceName || strcmp(deviceName, PlaybackDeviceList[i]) == 0))
+ if(!al_string_empty(*iter) &&
+ (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0))
{
- DeviceID = i;
+ DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices));
break;
}
}
- if(i == NumPlaybackDevices)
+ if(iter == end)
return ALC_INVALID_VALUE;
data = calloc(1, sizeof(*data));
@@ -329,20 +324,10 @@ retry_open:
goto failure;
}
- data->WaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if(data->WaveThreadEvent == NULL)
- {
- ERR("CreateEvent failed: %lu\n", GetLastError());
- goto failure;
- }
-
- Device->DeviceName = strdup(PlaybackDeviceList[DeviceID]);
+ al_string_copy(&Device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID));
return ALC_NO_ERROR;
failure:
- if(data->WaveThreadEvent)
- CloseHandle(data->WaveThreadEvent);
-
if(data->WaveHandle.Out)
waveOutClose(data->WaveHandle.Out);
@@ -356,9 +341,6 @@ static void WinMMClosePlayback(ALCdevice *device)
WinMMData *data = (WinMMData*)device->ExtraData;
// Close the Wave device
- CloseHandle(data->WaveThreadEvent);
- data->WaveThreadEvent = 0;
-
waveOutClose(data->WaveHandle.Out);
data->WaveHandle.Out = 0;
@@ -426,11 +408,11 @@ static ALCboolean WinMMStartPlayback(ALCdevice *device)
ALint BufferSize;
ALuint i;
- data->WaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &data->WaveThreadID);
- if(data->WaveThread == NULL)
+ data->killNow = AL_FALSE;
+ if(althrd_create(&data->thread, PlaybackThreadProc, device) != althrd_success)
return ALC_FALSE;
- data->WaveBuffersCommitted = 0;
+ InitRef(&data->WaveBuffersCommitted, 0);
// Create 4 Buffers
BufferSize = device->UpdateSize*device->NumUpdates / 4;
@@ -441,12 +423,12 @@ static ALCboolean WinMMStartPlayback(ALCdevice *device)
{
memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR));
data->WaveBuffer[i].dwBufferLength = BufferSize;
- data->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
+ data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
(data->WaveBuffer[i-1].lpData +
data->WaveBuffer[i-1].dwBufferLength));
waveOutPrepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR));
waveOutWrite(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR));
- InterlockedIncrement(&data->WaveBuffersCommitted);
+ IncrementRef(&data->WaveBuffersCommitted);
}
return ALC_TRUE;
@@ -458,19 +440,12 @@ static void WinMMStopPlayback(ALCdevice *device)
void *buffer = NULL;
int i;
- if(data->WaveThread == NULL)
+ if(data->killNow)
return;
// Set flag to stop processing headers
data->killNow = AL_TRUE;
-
- // Wait for signal that Wave Thread has been destroyed
- WaitForSingleObjectEx(data->WaveThreadEvent, 5000, FALSE);
-
- CloseHandle(data->WaveThread);
- data->WaveThread = 0;
-
- data->killNow = AL_FALSE;
+ althrd_join(data->thread, &i);
// Release the wave buffers
for(i = 0;i < 4;i++)
@@ -485,28 +460,31 @@ static void WinMMStopPlayback(ALCdevice *device)
static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
{
+ const al_string *iter, *end;
ALbyte *BufferData = NULL;
DWORD CapturedDataSize;
WinMMData *data = NULL;
- UINT DeviceID = 0;
ALint BufferSize;
+ UINT DeviceID;
MMRESULT res;
ALuint i;
- if(!CaptureDeviceList)
+ if(VECTOR_SIZE(CaptureDevices) == 0)
ProbeCaptureDevices();
// Find the Device ID matching the deviceName if valid
- for(i = 0;i < NumCaptureDevices;i++)
+ iter = VECTOR_ITER_BEGIN(CaptureDevices);
+ end = VECTOR_ITER_END(CaptureDevices);
+ for(;iter != end;iter++)
{
- if(CaptureDeviceList[i] &&
- (!deviceName || strcmp(deviceName, CaptureDeviceList[i]) == 0))
+ if(!al_string_empty(*iter) &&
+ (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0))
{
- DeviceID = i;
+ DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices));
break;
}
}
- if(i == NumCaptureDevices)
+ if(iter == end)
return ALC_INVALID_VALUE;
switch(Device->FmtChans)
@@ -560,13 +538,6 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
goto failure;
}
- data->WaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if(data->WaveThreadEvent == NULL)
- {
- ERR("CreateEvent failed: %lu\n", GetLastError());
- goto failure;
- }
-
// Allocate circular memory buffer for the captured audio
CapturedDataSize = Device->UpdateSize*Device->NumUpdates;
@@ -578,7 +549,7 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
if(!data->Ring)
goto failure;
- data->WaveBuffersCommitted = 0;
+ InitRef(&data->WaveBuffersCommitted, 0);
// Create 4 Buffers of 50ms each
BufferSize = data->Format.nAvgBytesPerSec / 20;
@@ -592,27 +563,23 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
{
memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR));
data->WaveBuffer[i].dwBufferLength = BufferSize;
- data->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
+ data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
(data->WaveBuffer[i-1].lpData +
data->WaveBuffer[i-1].dwBufferLength));
data->WaveBuffer[i].dwFlags = 0;
data->WaveBuffer[i].dwLoops = 0;
waveInPrepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
waveInAddBuffer(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
- InterlockedIncrement(&data->WaveBuffersCommitted);
+ IncrementRef(&data->WaveBuffersCommitted);
}
- data->WaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)Device, 0, &data->WaveThreadID);
- if (data->WaveThread == NULL)
+ if(althrd_create(&data->thread, CaptureThreadProc, Device) != althrd_success)
goto failure;
- Device->DeviceName = strdup(CaptureDeviceList[DeviceID]);
+ al_string_copy(&Device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID));
return ALC_NO_ERROR;
failure:
- if(data->WaveThread)
- CloseHandle(data->WaveThread);
-
if(BufferData)
{
for(i = 0;i < 4;i++)
@@ -623,9 +590,6 @@ failure:
if(data->Ring)
DestroyRingBuffer(data->Ring);
- if(data->WaveThreadEvent)
- CloseHandle(data->WaveThreadEvent);
-
if(data->WaveHandle.In)
waveInClose(data->WaveHandle.In);
@@ -642,16 +606,13 @@ static void WinMMCloseCapture(ALCdevice *Device)
/* Tell the processing thread to quit and wait for it to do so. */
data->killNow = AL_TRUE;
- PostThreadMessage(data->WaveThreadID, WM_QUIT, 0, 0);
+ PostThreadMessage(data->thread, WM_QUIT, 0, 0);
- WaitForSingleObjectEx(data->WaveThreadEvent, 5000, FALSE);
+ althrd_join(data->thread, &i);
/* Make sure capture is stopped and all pending buffers are flushed. */
waveInReset(data->WaveHandle.In);
- CloseHandle(data->WaveThread);
- data->WaveThread = 0;
-
// Release the wave buffers
for(i = 0;i < 4;i++)
{
@@ -665,9 +626,6 @@ static void WinMMCloseCapture(ALCdevice *Device)
data->Ring = NULL;
// Close the Wave device
- CloseHandle(data->WaveThreadEvent);
- data->WaveThreadEvent = 0;
-
waveInClose(data->WaveHandle.In);
data->WaveHandle.In = 0;
@@ -701,6 +659,17 @@ static ALCuint WinMMAvailableSamples(ALCdevice *Device)
}
+static inline void AppendAllDevicesList2(const al_string *name)
+{
+ if(!al_string_empty(*name))
+ AppendAllDevicesList(al_string_get_cstr(*name));
+}
+static inline void AppendCaptureDeviceList2(const al_string *name)
+{
+ if(!al_string_empty(*name))
+ AppendCaptureDeviceList(al_string_get_cstr(*name));
+}
+
static const BackendFuncs WinMMFuncs = {
WinMMOpenPlayback,
WinMMClosePlayback,
@@ -718,52 +687,34 @@ static const BackendFuncs WinMMFuncs = {
ALCboolean alcWinMMInit(BackendFuncs *FuncList)
{
+ VECTOR_INIT(PlaybackDevices);
+ VECTOR_INIT(CaptureDevices);
+
*FuncList = WinMMFuncs;
return ALC_TRUE;
}
void alcWinMMDeinit()
{
- ALuint i;
+ clear_devlist(&PlaybackDevices);
+ VECTOR_DEINIT(PlaybackDevices);
- for(i = 0;i < NumPlaybackDevices;i++)
- free(PlaybackDeviceList[i]);
- free(PlaybackDeviceList);
- PlaybackDeviceList = NULL;
-
- NumPlaybackDevices = 0;
-
-
- for(i = 0;i < NumCaptureDevices;i++)
- free(CaptureDeviceList[i]);
- free(CaptureDeviceList);
- CaptureDeviceList = NULL;
-
- NumCaptureDevices = 0;
+ clear_devlist(&CaptureDevices);
+ VECTOR_DEINIT(CaptureDevices);
}
void alcWinMMProbe(enum DevProbe type)
{
- ALuint i;
-
switch(type)
{
case ALL_DEVICE_PROBE:
ProbePlaybackDevices();
- for(i = 0;i < NumPlaybackDevices;i++)
- {
- if(PlaybackDeviceList[i])
- AppendAllDevicesList(PlaybackDeviceList[i]);
- }
+ VECTOR_FOR_EACH(const al_string, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
ProbeCaptureDevices();
- for(i = 0;i < NumCaptureDevices;i++)
- {
- if(CaptureDeviceList[i])
- AppendCaptureDeviceList(CaptureDeviceList[i]);
- }
+ VECTOR_FOR_EACH(const al_string, CaptureDevices, AppendCaptureDeviceList2);
break;
}
}
diff --git a/Alc/compat.h b/Alc/compat.h
index dbbcce28..f54ef9ce 100644
--- a/Alc/compat.h
+++ b/Alc/compat.h
@@ -1,56 +1,23 @@
#ifndef AL_COMPAT_H
#define AL_COMPAT_H
-#include "AL/al.h"
-
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-typedef DWORD althread_key_t;
-int althread_key_create(althread_key_t *key, void (*callback)(void*));
-int althread_key_delete(althread_key_t key);
-void *althread_getspecific(althread_key_t key);
-int althread_setspecific(althread_key_t key, void *val);
-
-typedef LONG althread_once_t;
-#define ALTHREAD_ONCE_INIT 0
-void althread_once(althread_once_t *once, void (*callback)(void));
-
-inline int alsched_yield(void)
-{ SwitchToThread(); return 0; }
-
WCHAR *strdupW(const WCHAR *str);
+/* Opens a file with standard I/O. The filename is expected to be UTF-8. */
+FILE *al_fopen(const char *fname, const char *mode);
+
#define HAVE_DYNLOAD 1
#else
-#include <pthread.h>
-
-typedef pthread_mutex_t CRITICAL_SECTION;
-void InitializeCriticalSection(CRITICAL_SECTION *cs);
-void DeleteCriticalSection(CRITICAL_SECTION *cs);
-void EnterCriticalSection(CRITICAL_SECTION *cs);
-void LeaveCriticalSection(CRITICAL_SECTION *cs);
-
-ALuint timeGetTime(void);
-void Sleep(ALuint t);
-
-#define althread_key_t pthread_key_t
-#define althread_key_create pthread_key_create
-#define althread_key_delete pthread_key_delete
-#define althread_getspecific pthread_getspecific
-#define althread_setspecific pthread_setspecific
-
-#define althread_once_t pthread_once_t
-#define ALTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
-#define althread_once pthread_once
-
-#define alsched_yield sched_yield
+#define al_fopen fopen
-#if defined(HAVE_DLFCN_H)
+#if defined(HAVE_DLFCN_H) && !defined(IN_IDE_PARSER)
#define HAVE_DYNLOAD 1
#endif
diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c
index 527e3be6..c8317c8b 100644
--- a/Alc/effects/autowah.c
+++ b/Alc/effects/autowah.c
@@ -71,8 +71,8 @@ static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, co
attackTime = slot->EffectProps.Autowah.AttackTime * state->Frequency;
releaseTime = slot->EffectProps.Autowah.ReleaseTime * state->Frequency;
- state->AttackRate = 1.0f / attackTime;
- state->ReleaseRate = 1.0f / releaseTime;
+ state->AttackRate = powf(1.0f/GAIN_SILENCE_THRESHOLD, 1.0f/attackTime);
+ state->ReleaseRate = powf(GAIN_SILENCE_THRESHOLD/1.0f, 1.0f/releaseTime);
state->PeakGain = slot->EffectProps.Autowah.PeakGain;
state->Resonance = slot->EffectProps.Autowah.Resonance;
@@ -102,9 +102,9 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo,
* incoming signal, and attack or release to reach it. */
amplitude = fabsf(smp);
if(amplitude > gain)
- gain = minf(gain+state->AttackRate, amplitude);
+ gain = minf(gain*state->AttackRate, amplitude);
else if(amplitude < gain)
- gain = maxf(gain-state->ReleaseRate, amplitude);
+ gain = maxf(gain*state->ReleaseRate, amplitude);
gain = maxf(gain, GAIN_SILENCE_THRESHOLD);
/* FIXME: What range does the filter cover? */
@@ -151,10 +151,7 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo,
}
}
-static void ALautowahState_Delete(ALautowahState *state)
-{
- free(state);
-}
+DECLARE_DEFAULT_ALLOCATORS(ALautowahState)
DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState);
@@ -167,13 +164,13 @@ static ALeffectState *ALautowahStateFactory_create(ALautowahStateFactory *UNUSED
{
ALautowahState *state;
- state = malloc(sizeof(*state));
+ state = ALautowahState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALautowahState, ALeffectState, state);
- state->AttackRate = 0.0f;
- state->ReleaseRate = 0.0f;
- state->Resonance = 0.0f;
+ state->AttackRate = 1.0f;
+ state->ReleaseRate = 1.0f;
+ state->Resonance = 2.0f;
state->PeakGain = 1.0f;
state->GainCtrl = 1.0f;
diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c
index 4945faf2..a6bb199e 100644
--- a/Alc/effects/chorus.c
+++ b/Alc/effects/chorus.c
@@ -30,6 +30,11 @@
#include "alu.h"
+enum ChorusWaveForm {
+ CWF_Triangle = AL_CHORUS_WAVEFORM_TRIANGLE,
+ CWF_Sinusoid = AL_CHORUS_WAVEFORM_SINUSOID
+};
+
typedef struct ALchorusState {
DERIVE_FROM_TYPE(ALeffectState);
@@ -44,7 +49,7 @@ typedef struct ALchorusState {
ALfloat Gain[2][MaxChannels];
/* effect parameters */
- ALint waveform;
+ enum ChorusWaveForm waveform;
ALint delay;
ALfloat depth;
ALfloat feedback;
@@ -92,7 +97,15 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons
ALfloat rate;
ALint phase;
- state->waveform = Slot->EffectProps.Chorus.Waveform;
+ switch(Slot->EffectProps.Chorus.Waveform)
+ {
+ case AL_CHORUS_WAVEFORM_TRIANGLE:
+ state->waveform = CWF_Triangle;
+ break;
+ case AL_CHORUS_WAVEFORM_SINUSOID:
+ state->waveform = CWF_Sinusoid;
+ break;
+ }
state->depth = Slot->EffectProps.Chorus.Depth;
state->feedback = Slot->EffectProps.Chorus.Feedback;
state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency);
@@ -115,10 +128,10 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons
state->lfo_range = fastf2u(frequency/rate + 0.5f);
switch(state->waveform)
{
- case AL_CHORUS_WAVEFORM_TRIANGLE:
+ case CWF_Triangle:
state->lfo_scale = 4.0f / state->lfo_range;
break;
- case AL_CHORUS_WAVEFORM_SINUSOID:
+ case CWF_Sinusoid:
state->lfo_scale = F_2PI / state->lfo_range;
break;
}
@@ -198,10 +211,15 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, co
ALfloat temps[64][2];
ALuint td = minu(SamplesToDo-base, 64);
- if(state->waveform == AL_CHORUS_WAVEFORM_TRIANGLE)
- ProcessTriangle(state, td, SamplesIn+base, temps);
- else if(state->waveform == AL_CHORUS_WAVEFORM_SINUSOID)
- ProcessSinusoid(state, td, SamplesIn+base, temps);
+ switch(state->waveform)
+ {
+ case CWF_Triangle:
+ ProcessTriangle(state, td, SamplesIn+base, temps);
+ break;
+ case CWF_Sinusoid:
+ ProcessSinusoid(state, td, SamplesIn+base, temps);
+ break;
+ }
for(kt = 0;kt < MaxChannels;kt++)
{
@@ -224,10 +242,7 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, co
}
}
-static void ALchorusState_Delete(ALchorusState *state)
-{
- free(state);
-}
+DECLARE_DEFAULT_ALLOCATORS(ALchorusState)
DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState);
@@ -240,7 +255,7 @@ static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(f
{
ALchorusState *state;
- state = malloc(sizeof(*state));
+ state = ALchorusState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALchorusState, ALeffectState, state);
@@ -249,6 +264,7 @@ static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(f
state->SampleBuffer[1] = NULL;
state->offset = 0;
state->lfo_range = 1;
+ state->waveform = CWF_Triangle;
return STATIC_CAST(ALeffectState, state);
}
diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c
index bab155c8..9728cabe 100644
--- a/Alc/effects/compressor.c
+++ b/Alc/effects/compressor.c
@@ -133,10 +133,7 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples
}
}
-static void ALcompressorState_Delete(ALcompressorState *state)
-{
- free(state);
-}
+DECLARE_DEFAULT_ALLOCATORS(ALcompressorState)
DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState);
@@ -149,7 +146,7 @@ static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *
{
ALcompressorState *state;
- state = malloc(sizeof(*state));
+ state = ALcompressorState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALcompressorState, ALeffectState, state);
diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c
index fe57c7d8..89af1c84 100644
--- a/Alc/effects/dedicated.c
+++ b/Alc/effects/dedicated.c
@@ -76,10 +76,7 @@ static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesTo
}
}
-static void ALdedicatedState_Delete(ALdedicatedState *state)
-{
- free(state);
-}
+DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState)
DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState);
@@ -93,7 +90,7 @@ ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(fa
ALdedicatedState *state;
ALsizei s;
- state = malloc(sizeof(*state));
+ state = ALdedicatedState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALdedicatedState, ALeffectState, state);
diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c
index e39a8197..b535655b 100644
--- a/Alc/effects/distortion.c
+++ b/Alc/effects/distortion.c
@@ -170,10 +170,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples
}
}
-static void ALdistortionState_Delete(ALdistortionState *state)
-{
- free(state);
-}
+DECLARE_DEFAULT_ALLOCATORS(ALdistortionState)
DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState);
@@ -186,7 +183,7 @@ static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory *
{
ALdistortionState *state;
- state = malloc(sizeof(*state));
+ state = ALdistortionState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALdistortionState, ALeffectState, state);
diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c
index 7471c3dd..049ae9c7 100644
--- a/Alc/effects/echo.c
+++ b/Alc/effects/echo.c
@@ -97,7 +97,7 @@ static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const AL
ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf,
1.0f - Slot->EffectProps.Echo.Damping,
- (ALfloat)LOWPASSFREQREF/frequency, 0.0f);
+ LOWPASSFREQREF/frequency, 0.0f);
gain = Slot->Gain;
dirGain = fabsf(lrpan);
@@ -161,10 +161,7 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const
state->Offset = offset;
}
-static void ALechoState_Delete(ALechoState *state)
-{
- free(state);
-}
+DECLARE_DEFAULT_ALLOCATORS(ALechoState)
DEFINE_ALEFFECTSTATE_VTABLE(ALechoState);
@@ -177,7 +174,7 @@ ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory))
{
ALechoState *state;
- state = malloc(sizeof(*state));
+ state = ALechoState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALechoState, ALeffectState, state);
diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c
index d5bd2caf..cfe7c46c 100644
--- a/Alc/effects/equalizer.c
+++ b/Alc/effects/equalizer.c
@@ -155,10 +155,7 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo
}
}
-static void ALequalizerState_Delete(ALequalizerState *state)
-{
- free(state);
-}
+DECLARE_DEFAULT_ALLOCATORS(ALequalizerState)
DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState);
@@ -172,7 +169,7 @@ ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(fa
ALequalizerState *state;
int it;
- state = malloc(sizeof(*state));
+ state = ALequalizerState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALequalizerState, ALeffectState, state);
diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c
index a94cd365..117cd1f2 100644
--- a/Alc/effects/flanger.c
+++ b/Alc/effects/flanger.c
@@ -30,6 +30,11 @@
#include "alu.h"
+enum FlangerWaveForm {
+ FWF_Triangle = AL_FLANGER_WAVEFORM_TRIANGLE,
+ FWF_Sinusoid = AL_FLANGER_WAVEFORM_SINUSOID
+};
+
typedef struct ALflangerState {
DERIVE_FROM_TYPE(ALeffectState);
@@ -44,7 +49,7 @@ typedef struct ALflangerState {
ALfloat Gain[2][MaxChannels];
/* effect parameters */
- ALint waveform;
+ enum FlangerWaveForm waveform;
ALint delay;
ALfloat depth;
ALfloat feedback;
@@ -92,7 +97,15 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co
ALfloat rate;
ALint phase;
- state->waveform = Slot->EffectProps.Flanger.Waveform;
+ switch(Slot->EffectProps.Flanger.Waveform)
+ {
+ case AL_FLANGER_WAVEFORM_TRIANGLE:
+ state->waveform = FWF_Triangle;
+ break;
+ case AL_FLANGER_WAVEFORM_SINUSOID:
+ state->waveform = FWF_Sinusoid;
+ break;
+ }
state->depth = Slot->EffectProps.Flanger.Depth;
state->feedback = Slot->EffectProps.Flanger.Feedback;
state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency);
@@ -115,10 +128,10 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co
state->lfo_range = fastf2u(frequency/rate + 0.5f);
switch(state->waveform)
{
- case AL_FLANGER_WAVEFORM_TRIANGLE:
+ case FWF_Triangle:
state->lfo_scale = 4.0f / state->lfo_range;
break;
- case AL_FLANGER_WAVEFORM_SINUSOID:
+ case FWF_Sinusoid:
state->lfo_scale = F_2PI / state->lfo_range;
break;
}
@@ -198,10 +211,15 @@ static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo,
ALfloat temps[64][2];
ALuint td = minu(SamplesToDo-base, 64);
- if(state->waveform == AL_FLANGER_WAVEFORM_TRIANGLE)
- ProcessTriangle(state, td, SamplesIn+base, temps);
- else if(state->waveform == AL_FLANGER_WAVEFORM_SINUSOID)
- ProcessSinusoid(state, td, SamplesIn+base, temps);
+ switch(state->waveform)
+ {
+ case FWF_Triangle:
+ ProcessTriangle(state, td, SamplesIn+base, temps);
+ break;
+ case FWF_Sinusoid:
+ ProcessSinusoid(state, td, SamplesIn+base, temps);
+ break;
+ }
for(kt = 0;kt < MaxChannels;kt++)
{
@@ -224,10 +242,7 @@ static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo,
}
}
-static void ALflangerState_Delete(ALflangerState *state)
-{
- free(state);
-}
+DECLARE_DEFAULT_ALLOCATORS(ALflangerState)
DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState);
@@ -240,7 +255,7 @@ ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factor
{
ALflangerState *state;
- state = malloc(sizeof(*state));
+ state = ALflangerState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALflangerState, ALeffectState, state);
@@ -249,6 +264,7 @@ ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factor
state->SampleBuffer[1] = NULL;
state->offset = 0;
state->lfo_range = 1;
+ state->waveform = FWF_Triangle;
return STATIC_CAST(ALeffectState, state);
}
diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c
index 17ca7e17..a5475708 100644
--- a/Alc/effects/modulator.c
+++ b/Alc/effects/modulator.c
@@ -171,10 +171,7 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesTo
}
}
-static void ALmodulatorState_Delete(ALmodulatorState *state)
-{
- free(state);
-}
+DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState)
DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState);
@@ -187,7 +184,7 @@ static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UN
{
ALmodulatorState *state;
- state = malloc(sizeof(*state));
+ state = ALmodulatorState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALmodulatorState, ALeffectState, state);
diff --git a/Alc/effects/null.c b/Alc/effects/null.c
index 816a2525..6dacd021 100644
--- a/Alc/effects/null.c
+++ b/Alc/effects/null.c
@@ -48,10 +48,20 @@ static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samp
(void)samplesOut;
}
-/* This frees the memory used by the object, after it has been destructed. */
-static void ALnullState_Delete(ALnullState *state)
+/* This allocates memory to store the object, before it gets constructed.
+ * DECLARE_DEFAULT_ALLOCATORS can be used to declate a default method.
+ */
+static void *ALnullState_New(size_t size)
+{
+ return malloc(size);
+}
+
+/* This frees the memory used by the object, after it has been destructed.
+ * DECLARE_DEFAULT_ALLOCATORS can be used to declate a default method.
+ */
+static void ALnullState_Delete(void *ptr)
{
- free(state);
+ free(ptr);
}
/* Define the forwards and the ALeffectState vtable for this type. */
@@ -67,7 +77,7 @@ ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory))
{
ALnullState *state;
- state = calloc(1, sizeof(*state));
+ state = ALnullState_New(sizeof(*state));
if(!state) return NULL;
/* Set vtables for inherited types. */
SET_VTABLE2(ALnullState, ALeffectState, state);
diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c
index 75ec76e3..245aed41 100644
--- a/Alc/effects/reverb.c
+++ b/Alc/effects/reverb.c
@@ -1096,7 +1096,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, cons
}
else
{
- hfscale = (ALfloat)LOWPASSFREQREF / frequency;
+ hfscale = LOWPASSFREQREF / frequency;
ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
Slot->EffectProps.Reverb.GainHF,
hfscale, 0.0f);
@@ -1170,10 +1170,7 @@ static ALvoid ALreverbState_Destruct(ALreverbState *State)
State->SampleBuffer = NULL;
}
-static void ALreverbState_Delete(ALreverbState *state)
-{
- free(state);
-}
+DECLARE_DEFAULT_ALLOCATORS(ALreverbState)
DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState);
@@ -1187,7 +1184,7 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f
ALreverbState *state;
ALuint index;
- state = malloc(sizeof(ALreverbState));
+ state = ALreverbState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALreverbState, ALeffectState, state);
diff --git a/Alc/helpers.c b/Alc/helpers.c
index f8a5f13b..e1220fd4 100644
--- a/Alc/helpers.c
+++ b/Alc/helpers.c
@@ -18,6 +18,14 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
+#ifdef _WIN32
+#ifdef __MINGW32__
+#define _WIN32_IE 0x501
+#else
+#define _WIN32_IE 0x400
+#endif
+#endif
+
#include "config.h"
#include <stdlib.h>
@@ -71,24 +79,20 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
#include <ieeefp.h>
#endif
+#ifdef _WIN32_IE
+#include <shlobj.h>
+#endif
+
#include "alMain.h"
+#include "alu.h"
#include "atomic.h"
#include "uintmap.h"
+#include "vector.h"
+#include "alstring.h"
#include "compat.h"
+#include "threads.h"
-extern inline RefCount IncrementRef(volatile RefCount *ptr);
-extern inline RefCount DecrementRef(volatile RefCount *ptr);
-extern inline int ExchangeInt(volatile int *ptr, int newval);
-extern inline void *ExchangePtr(XchgPtr *ptr, void *newval);
-extern inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval);
-extern inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval);
-
-extern inline void LockUIntMapRead(UIntMap *map);
-extern inline void UnlockUIntMapRead(UIntMap *map);
-extern inline void LockUIntMapWrite(UIntMap *map);
-extern inline void UnlockUIntMapWrite(UIntMap *map);
-
extern inline ALuint NextPowerOf2(ALuint value);
extern inline ALint fastf2i(ALfloat f);
extern inline ALuint fastf2u(ALfloat f);
@@ -135,7 +139,11 @@ void FillCPUCaps(ALuint capfilter)
{
caps |= CPU_CAP_SSE;
if((cpuinf[0].regs[3]&(1<<26)))
+ {
caps |= CPU_CAP_SSE2;
+ if((cpuinf[0].regs[2]&(1<<19)))
+ caps |= CPU_CAP_SSE4_1;
+ }
}
}
}
@@ -160,10 +168,13 @@ void FillCPUCaps(ALuint capfilter)
caps |= CPU_CAP_NEON;
#endif
- TRACE("Got caps:%s%s%s%s\n", ((caps&CPU_CAP_SSE)?((capfilter&CPU_CAP_SSE)?" SSE":" (SSE)"):""),
- ((caps&CPU_CAP_SSE2)?((capfilter&CPU_CAP_SSE2)?" SSE2":" (SSE2)"):""),
- ((caps&CPU_CAP_NEON)?((capfilter&CPU_CAP_NEON)?" Neon":" (Neon)"):""),
- ((!caps)?" -none-":""));
+ TRACE("Extensions:%s%s%s%s%s\n",
+ ((capfilter&CPU_CAP_SSE) ? ((caps&CPU_CAP_SSE) ? " +SSE" : " -SSE") : ""),
+ ((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""),
+ ((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""),
+ ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +Neon" : " -Neon") : ""),
+ ((!capfilter) ? " -none-" : "")
+ );
CPUCapFlags = caps & capfilter;
}
@@ -294,46 +305,36 @@ void RestoreFPUMode(const FPUCtl *ctl)
#ifdef _WIN32
-extern inline int alsched_yield(void);
-void althread_once(althread_once_t *once, void (*callback)(void))
+static WCHAR *FromUTF8(const char *str)
{
- LONG ret;
- while((ret=InterlockedExchange(once, 1)) == 1)
- alsched_yield();
- if(ret == 0)
- callback();
- InterlockedExchange(once, 2);
-}
-
+ WCHAR *out = NULL;
+ int len;
-int althread_key_create(althread_key_t *key, void (*callback)(void*))
-{
- *key = TlsAlloc();
- if(callback)
- InsertUIntMapEntry(&TlsDestructor, *key, callback);
- return 0;
-}
-
-int althread_key_delete(althread_key_t key)
-{
- InsertUIntMapEntry(&TlsDestructor, key, NULL);
- TlsFree(key);
- return 0;
+ 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;
}
-void *althread_getspecific(althread_key_t key)
-{ return TlsGetValue(key); }
-int althread_setspecific(althread_key_t key, void *val)
+void *LoadLib(const char *name)
{
- TlsSetValue(key, val);
- return 0;
-}
-
+ HANDLE hdl = NULL;
+ WCHAR *wname;
-void *LoadLib(const char *name)
-{ return LoadLibraryA(name); }
+ wname = FromUTF8(name);
+ if(!wname)
+ ERR("Failed to convert UTF-8 filename: \"%s\"\n", name);
+ else
+ {
+ hdl = LoadLibraryW(wname);
+ free(wname);
+ }
+ return hdl;
+}
void CloseLib(void *handle)
{ FreeLibrary((HANDLE)handle); }
void *GetSymbol(void *handle, const char *name)
@@ -362,97 +363,27 @@ WCHAR *strdupW(const WCHAR *str)
return ret;
}
-#else
-
-#include <pthread.h>
-#ifdef HAVE_PTHREAD_NP_H
-#include <pthread_np.h>
-#endif
-#include <sched.h>
-#include <time.h>
-#include <sys/time.h>
-
-void InitializeCriticalSection(CRITICAL_SECTION *cs)
+FILE *al_fopen(const char *fname, const char *mode)
{
- pthread_mutexattr_t attrib;
- int ret;
+ WCHAR *wname=NULL, *wmode=NULL;
+ FILE *file = NULL;
- ret = pthread_mutexattr_init(&attrib);
- assert(ret == 0);
+ wname = FromUTF8(fname);
+ wmode = FromUTF8(mode);
+ if(!wname)
+ ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
+ else if(!wmode)
+ ERR("Failed to convert UTF-8 mode: \"%s\"\n", mode);
+ else
+ file = _wfopen(wname, wmode);
- ret = pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE);
-#ifdef HAVE_PTHREAD_NP_H
- if(ret != 0)
- ret = pthread_mutexattr_setkind_np(&attrib, PTHREAD_MUTEX_RECURSIVE);
-#endif
- assert(ret == 0);
- ret = pthread_mutex_init(cs, &attrib);
- assert(ret == 0);
+ free(wname);
+ free(wmode);
- pthread_mutexattr_destroy(&attrib);
-}
-void DeleteCriticalSection(CRITICAL_SECTION *cs)
-{
- int ret;
- ret = pthread_mutex_destroy(cs);
- assert(ret == 0);
-}
-void EnterCriticalSection(CRITICAL_SECTION *cs)
-{
- int ret;
- ret = pthread_mutex_lock(cs);
- assert(ret == 0);
-}
-void LeaveCriticalSection(CRITICAL_SECTION *cs)
-{
- int ret;
- ret = pthread_mutex_unlock(cs);
- assert(ret == 0);
+ return file;
}
-/* NOTE: This wrapper isn't quite accurate as it returns an ALuint, as opposed
- * to the expected DWORD. Both are defined as unsigned 32-bit types, however.
- * Additionally, Win32 is supposed to measure the time since Windows started,
- * as opposed to the actual time. */
-ALuint timeGetTime(void)
-{
-#if _POSIX_TIMERS > 0
- struct timespec ts;
- int ret = -1;
-
-#if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0)
-#if _POSIX_MONOTONIC_CLOCK == 0
- static int hasmono = 0;
- if(hasmono > 0 || (hasmono == 0 &&
- (hasmono=sysconf(_SC_MONOTONIC_CLOCK)) > 0))
-#endif
- ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-#endif
- if(ret != 0)
- ret = clock_gettime(CLOCK_REALTIME, &ts);
- assert(ret == 0);
-
- return ts.tv_nsec/1000000 + ts.tv_sec*1000;
#else
- struct timeval tv;
- int ret;
-
- ret = gettimeofday(&tv, NULL);
- assert(ret == 0);
-
- return tv.tv_usec/1000 + tv.tv_sec*1000;
-#endif
-}
-
-void Sleep(ALuint t)
-{
- struct timespec tv, rem;
- tv.tv_nsec = (t*1000000)%1000000000;
- tv.tv_sec = t/1000;
-
- while(nanosleep(&tv, &rem) == -1 && errno == EINTR)
- tv = rem;
-}
#ifdef HAVE_DLFCN_H
@@ -500,6 +431,135 @@ void al_print(const char *type, const char *func, const char *fmt, ...)
fflush(LogFile);
}
+#ifdef _WIN32
+static inline int is_slash(int c)
+{ return (c == '\\' || c == '/'); }
+
+FILE *OpenDataFile(const char *fname, const char *subdir)
+{
+ static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
+ WCHAR *wname=NULL, *wsubdir=NULL;
+ int i;
+
+ /* If the path is absolute, open it directly. */
+ if(fname[0] != '\0' && fname[1] == ':' && is_slash(fname[2]))
+ {
+ FILE *f;
+ if((f=al_fopen(fname, "rb")) != NULL)
+ {
+ TRACE("Opened %s\n", fname);
+ return f;
+ }
+ WARN("Could not open %s\n", fname);
+ return NULL;
+ }
+
+ wname = FromUTF8(fname);
+ wsubdir = FromUTF8(subdir);
+ if(!wname)
+ ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
+ else if(!wsubdir)
+ ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir);
+ else for(i = 0;i < 2;i++)
+ {
+ WCHAR buffer[PATH_MAX];
+ size_t len;
+ FILE *f;
+
+ if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) == FALSE)
+ continue;
+
+ len = lstrlenW(buffer);
+ if(len > 0 && is_slash(buffer[len-1]))
+ buffer[--len] = '\0';
+ _snwprintf(buffer+len, PATH_MAX-len, L"/%ls/%ls", wsubdir, wname);
+ len = lstrlenW(buffer);
+ while(len > 0)
+ {
+ --len;
+ if(buffer[len] == '/')
+ buffer[len] = '\\';
+ }
+
+ if((f=_wfopen(buffer, L"rb")) != NULL)
+ {
+ TRACE("Opened %ls\n", buffer);
+ return f;
+ }
+ WARN("Could not open %ls\n", buffer);
+ }
+ free(wname);
+ free(wsubdir);
+
+ return NULL;
+}
+#else
+FILE *OpenDataFile(const char *fname, const char *subdir)
+{
+ char buffer[PATH_MAX] = "";
+ const char *str, *next;
+ FILE *f;
+
+ if(fname[0] == '/')
+ {
+ if((f=al_fopen(fname, "rb")) != NULL)
+ {
+ TRACE("Opened %s\n", fname);
+ return f;
+ }
+ WARN("Could not open %s\n", fname);
+ return NULL;
+ }
+
+ if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
+ snprintf(buffer, sizeof(buffer), "%s/%s/%s", str, subdir, fname);
+ else if((str=getenv("HOME")) != NULL && str[0] != '\0')
+ snprintf(buffer, sizeof(buffer), "%s/.local/share/%s/%s", str, subdir, fname);
+ if(buffer[0])
+ {
+ if((f=al_fopen(buffer, "rb")) != NULL)
+ {
+ TRACE("Opened %s\n", buffer);
+ return f;
+ }
+ WARN("Could not open %s\n", buffer);
+ }
+
+ if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0')
+ str = "/usr/local/share/:/usr/share/";
+
+ next = str;
+ while((str=next) != NULL && str[0] != '\0')
+ {
+ size_t len;
+ next = strchr(str, ':');
+
+ if(!next)
+ len = strlen(str);
+ else
+ {
+ len = next - str;
+ next++;
+ }
+
+ if(len > sizeof(buffer)-1)
+ len = sizeof(buffer)-1;
+ strncpy(buffer, str, len);
+ buffer[len] = '\0';
+ snprintf(buffer+len, sizeof(buffer)-len, "/%s/%s", subdir, fname);
+
+ if((f=al_fopen(buffer, "rb")) != NULL)
+ {
+ TRACE("Opened %s\n", buffer);
+ return f;
+ }
+ WARN("Could not open %s\n", buffer);
+ }
+
+ return NULL;
+}
+#endif
+
void SetRTPriority(void)
{
@@ -526,183 +586,172 @@ void SetRTPriority(void)
}
-static void Lock(volatile ALenum *l)
+ALboolean vector_reserve(void *ptr, size_t base_size, size_t obj_count, size_t obj_size, ALboolean exact)
{
- while(ExchangeInt(l, AL_TRUE) == AL_TRUE)
- alsched_yield();
+ vector_ *vecptr = ptr;
+ if((size_t)(*vecptr ? (*vecptr)->Capacity : 0) < obj_count)
+ {
+ ALsizei old_size = (*vecptr ? (*vecptr)->Size : 0);
+ void *temp;
+
+ /* Limit vector sizes to the greatest power-of-two value that an
+ * ALsizei can hold. */
+ if(obj_count > (INT_MAX>>1)+1)
+ return AL_FALSE;
+
+ /* Use the next power-of-2 size if we don't need to allocate the exact
+ * amount. This is preferred when regularly increasing the vector since
+ * it means fewer reallocations. Though it means it also wastes some
+ * memory. */
+ if(exact == AL_FALSE)
+ obj_count = NextPowerOf2((ALuint)obj_count);
+
+ /* Need to be explicit with the caller type's base size, because it
+ * could have extra padding before the start of the array (that is,
+ * sizeof(*vector_) may not equal base_size). */
+ temp = realloc(*vecptr, base_size + obj_size*obj_count);
+ if(temp == NULL) return AL_FALSE;
+
+ *vecptr = temp;
+ (*vecptr)->Capacity = (ALsizei)obj_count;
+ (*vecptr)->Size = old_size;
+ }
+ return AL_TRUE;
}
-static void Unlock(volatile ALenum *l)
+ALboolean vector_resize(void *ptr, size_t base_size, size_t obj_count, size_t obj_size)
{
- ExchangeInt(l, AL_FALSE);
+ vector_ *vecptr = ptr;
+ if(*vecptr || obj_count > 0)
+ {
+ if(!vector_reserve(vecptr, base_size, obj_count, obj_size, AL_TRUE))
+ return AL_FALSE;
+ (*vecptr)->Size = (ALsizei)obj_count;
+ }
+ return AL_TRUE;
}
-void RWLockInit(RWLock *lock)
+ALboolean vector_insert(void *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend)
{
- lock->read_count = 0;
- lock->write_count = 0;
- lock->read_lock = AL_FALSE;
- lock->read_entry_lock = AL_FALSE;
- lock->write_lock = AL_FALSE;
+ vector_ *vecptr = ptr;
+ if(datstart != datend)
+ {
+ ptrdiff_t ins_elem = ((char*)ins_pos - ((char*)(*vecptr) + base_size)) / obj_size;
+ ptrdiff_t numins = ((const char*)datend - (const char*)datstart) / obj_size;
+
+ assert(numins > 0);
+ if(INT_MAX-VECTOR_SIZE(*vecptr) <= numins ||
+ !vector_reserve(vecptr, base_size, VECTOR_SIZE(*vecptr)+numins, obj_size, AL_TRUE))
+ return AL_FALSE;
+
+ /* NOTE: ins_pos may have been invalidated if *vecptr moved. Use ins_elem instead. */
+ if(ins_elem < (*vecptr)->Size)
+ {
+ memmove((char*)(*vecptr) + base_size + ((ins_elem+numins)*obj_size),
+ (char*)(*vecptr) + base_size + ((ins_elem )*obj_size),
+ ((*vecptr)->Size-ins_elem)*obj_size);
+ }
+ memcpy((char*)(*vecptr) + base_size + (ins_elem*obj_size),
+ datstart, numins*obj_size);
+ (*vecptr)->Size += (ALsizei)numins;
+ }
+ return AL_TRUE;
}
-void ReadLock(RWLock *lock)
+
+extern inline ALsizei al_string_length(const_al_string str);
+extern inline ALboolean al_string_empty(const_al_string str);
+extern inline const al_string_char_type *al_string_get_cstr(const_al_string str);
+
+void al_string_clear(al_string *str)
{
- Lock(&lock->read_entry_lock);
- Lock(&lock->read_lock);
- if(IncrementRef(&lock->read_count) == 1)
- Lock(&lock->write_lock);
- Unlock(&lock->read_lock);
- Unlock(&lock->read_entry_lock);
+ /* Reserve one more character than the total size of the string. This is to
+ * ensure we have space to add a null terminator in the string data so it
+ * can be used as a C-style string. */
+ VECTOR_RESERVE(*str, 1);
+ VECTOR_RESIZE(*str, 0);
+ *VECTOR_ITER_END(*str) = 0;
}
-void ReadUnlock(RWLock *lock)
+static inline int al_string_compare(const al_string_char_type *str1, ALsizei str1len,
+ const al_string_char_type *str2, ALsizei str2len)
{
- if(DecrementRef(&lock->read_count) == 0)
- Unlock(&lock->write_lock);
+ ALsizei complen = mini(str1len, str2len);
+ int ret = memcmp(str1, str2, complen);
+ if(ret == 0)
+ {
+ if(str1len > str2len) return 1;
+ if(str1len < str2len) return -1;
+ }
+ return ret;
}
-
-void WriteLock(RWLock *lock)
+int al_string_cmp(const_al_string str1, const_al_string str2)
{
- if(IncrementRef(&lock->write_count) == 1)
- Lock(&lock->read_lock);
- Lock(&lock->write_lock);
+ return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1),
+ &VECTOR_FRONT(str2), al_string_length(str2));
}
-
-void WriteUnlock(RWLock *lock)
+int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2)
{
- Unlock(&lock->write_lock);
- if(DecrementRef(&lock->write_count) == 0)
- Unlock(&lock->read_lock);
+ return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1),
+ str2, (ALsizei)strlen(str2));
}
-
-void InitUIntMap(UIntMap *map, ALsizei limit)
+void al_string_copy(al_string *str, const_al_string from)
{
- map->array = NULL;
- map->size = 0;
- map->maxsize = 0;
- map->limit = limit;
- RWLockInit(&map->lock);
+ ALsizei len = VECTOR_SIZE(from);
+ VECTOR_RESERVE(*str, len+1);
+ VECTOR_RESIZE(*str, 0);
+ VECTOR_INSERT(*str, VECTOR_ITER_END(*str), VECTOR_ITER_BEGIN(from), VECTOR_ITER_BEGIN(from)+len);
+ *VECTOR_ITER_END(*str) = 0;
}
-void ResetUIntMap(UIntMap *map)
+void al_string_copy_cstr(al_string *str, const al_string_char_type *from)
{
- WriteLock(&map->lock);
- free(map->array);
- map->array = NULL;
- map->size = 0;
- map->maxsize = 0;
- WriteUnlock(&map->lock);
+ size_t len = strlen(from);
+ VECTOR_RESERVE(*str, len+1);
+ VECTOR_RESIZE(*str, 0);
+ VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, from+len);
+ *VECTOR_ITER_END(*str) = 0;
}
-ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value)
+void al_string_append_char(al_string *str, const al_string_char_type c)
{
- ALsizei pos = 0;
+ VECTOR_RESERVE(*str, al_string_length(*str)+2);
+ VECTOR_PUSH_BACK(*str, c);
+ *VECTOR_ITER_END(*str) = 0;
+}
- WriteLock(&map->lock);
- if(map->size > 0)
+void al_string_append_cstr(al_string *str, const al_string_char_type *from)
+{
+ size_t len = strlen(from);
+ if(len != 0)
{
- ALsizei low = 0;
- ALsizei high = map->size - 1;
- while(low < high)
- {
- ALsizei mid = low + (high-low)/2;
- if(map->array[mid].key < key)
- low = mid + 1;
- else
- high = mid;
- }
- if(map->array[low].key < key)
- low++;
- pos = low;
+ VECTOR_RESERVE(*str, al_string_length(*str)+len+1);
+ VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, from+len);
+ *VECTOR_ITER_END(*str) = 0;
}
-
- if(pos == map->size || map->array[pos].key != key)
- {
- if(map->size == map->limit)
- {
- WriteUnlock(&map->lock);
- return AL_OUT_OF_MEMORY;
- }
-
- if(map->size == map->maxsize)
- {
- ALvoid *temp = NULL;
- ALsizei newsize;
-
- newsize = (map->maxsize ? (map->maxsize<<1) : 4);
- if(newsize >= map->maxsize)
- temp = realloc(map->array, newsize*sizeof(map->array[0]));
- if(!temp)
- {
- WriteUnlock(&map->lock);
- return AL_OUT_OF_MEMORY;
- }
- map->array = temp;
- map->maxsize = newsize;
- }
-
- if(pos < map->size)
- memmove(&map->array[pos+1], &map->array[pos],
- (map->size-pos)*sizeof(map->array[0]));
- map->size++;
- }
- map->array[pos].key = key;
- map->array[pos].value = value;
- WriteUnlock(&map->lock);
-
- return AL_NO_ERROR;
}
-ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key)
+void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to)
{
- ALvoid *ptr = NULL;
- WriteLock(&map->lock);
- if(map->size > 0)
+ if(to != from)
{
- ALsizei low = 0;
- ALsizei high = map->size - 1;
- while(low < high)
- {
- ALsizei mid = low + (high-low)/2;
- if(map->array[mid].key < key)
- low = mid + 1;
- else
- high = mid;
- }
- if(map->array[low].key == key)
- {
- ptr = map->array[low].value;
- if(low < map->size-1)
- memmove(&map->array[low], &map->array[low+1],
- (map->size-1-low)*sizeof(map->array[0]));
- map->size--;
- }
+ VECTOR_RESERVE(*str, al_string_length(*str)+(to-from)+1);
+ VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, to);
+ *VECTOR_ITER_END(*str) = 0;
}
- WriteUnlock(&map->lock);
- return ptr;
}
-ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key)
+#ifdef _WIN32
+void al_string_copy_wcstr(al_string *str, const wchar_t *from)
{
- ALvoid *ptr = NULL;
- ReadLock(&map->lock);
- if(map->size > 0)
+ int len;
+ if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0)
{
- ALsizei low = 0;
- ALsizei high = map->size - 1;
- while(low < high)
- {
- ALsizei mid = low + (high-low)/2;
- if(map->array[mid].key < key)
- low = mid + 1;
- else
- high = mid;
- }
- if(map->array[low].key == key)
- ptr = map->array[low].value;
+ VECTOR_RESERVE(*str, len);
+ VECTOR_RESIZE(*str, len-1);
+ WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, NULL, NULL);
+ *VECTOR_ITER_END(*str) = 0;
}
- ReadUnlock(&map->lock);
- return ptr;
}
+#endif
diff --git a/Alc/hrtf.c b/Alc/hrtf.c
index 49bb97a3..a0f8833b 100644
--- a/Alc/hrtf.c
+++ b/Alc/hrtf.c
@@ -28,11 +28,7 @@
#include "alMain.h"
#include "alSource.h"
#include "alu.h"
-
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
+#include "hrtf.h"
/* Current data set limits defined by the makehrtf utility. */
@@ -62,16 +58,6 @@ struct Hrtf {
static const ALchar magicMarker00[8] = "MinPHR00";
static const ALchar magicMarker01[8] = "MinPHR01";
-/* Define the default HRTF:
- * ALubyte defaultAzCount [DefaultHrtf.evCount]
- * ALushort defaultEvOffset [DefaultHrtf.evCount]
- * ALshort defaultCoeffs [DefaultHrtf.irCount * defaultHrtf.irSize]
- * ALubyte defaultDelays [DefaultHrtf.irCount]
- *
- * struct Hrtf DefaultHrtf
- */
-#include "hrtf_tables.inc"
-
static struct Hrtf *LoadedHrtfs = NULL;
/* Calculate the elevation indices given the polar elevation in radians.
@@ -664,24 +650,25 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
static struct Hrtf *LoadHrtf(ALuint deviceRate)
{
- const char *fnamelist = NULL;
+ const char *fnamelist = "default-%r.mhr";
- if(!ConfigValueStr(NULL, "hrtf_tables", &fnamelist))
- return NULL;
+ ConfigValueStr(NULL, "hrtf_tables", &fnamelist);
while(*fnamelist != '\0')
{
struct Hrtf *Hrtf = NULL;
char fname[PATH_MAX];
+ const char *next;
ALchar magic[8];
ALuint i;
FILE *f;
+ i = 0;
while(isspace(*fnamelist) || *fnamelist == ',')
fnamelist++;
- i = 0;
- while(*fnamelist != '\0' && *fnamelist != ',')
+ next = fnamelist;
+ while(*(fnamelist=next) != '\0' && *fnamelist != ',')
{
- const char *next = strpbrk(fnamelist, "%,");
+ next = strpbrk(fnamelist, "%,");
while(fnamelist != next && *fnamelist && i < sizeof(fname))
fname[i++] = *(fnamelist++);
@@ -704,7 +691,6 @@ static struct Hrtf *LoadHrtf(ALuint deviceRate)
}
else
ERR("Invalid marker '%%%c'\n", *next);
- fnamelist = next;
}
i = minu(i, sizeof(fname)-1);
fname[i] = '\0';
@@ -716,7 +702,7 @@ static struct Hrtf *LoadHrtf(ALuint deviceRate)
continue;
TRACE("Loading %s...\n", fname);
- f = fopen(fname, "rb");
+ f = OpenDataFile(fname, "openal/hrtf");
if(f == NULL)
{
ERR("Could not open %s\n", fname);
@@ -774,37 +760,31 @@ const struct Hrtf *GetHrtf(ALCdevice *device)
Hrtf = LoadHrtf(device->Frequency);
if(Hrtf != NULL)
return Hrtf;
-
- if(device->Frequency == DefaultHrtf.sampleRate)
- return &DefaultHrtf;
}
ERR("Incompatible format: %s %uhz\n",
DevFmtChannelsString(device->FmtChans), device->Frequency);
return NULL;
}
-void FindHrtfFormat(const ALCdevice *device, enum DevFmtChannels *chans, ALCuint *srate)
+ALCboolean FindHrtfFormat(const ALCdevice *device, enum DevFmtChannels *chans, ALCuint *srate)
{
- const struct Hrtf *hrtf = &DefaultHrtf;
-
- if(device->Frequency != DefaultHrtf.sampleRate)
+ const struct Hrtf *hrtf = LoadedHrtfs;
+ while(hrtf != NULL)
{
- hrtf = LoadedHrtfs;
- while(hrtf != NULL)
- {
- if(device->Frequency == hrtf->sampleRate)
- break;
- hrtf = hrtf->next;
- }
+ if(device->Frequency == hrtf->sampleRate)
+ break;
+ hrtf = hrtf->next;
+ }
- if(hrtf == NULL)
- hrtf = LoadHrtf(device->Frequency);
- if(hrtf == NULL)
- hrtf = &DefaultHrtf;
+ if(hrtf == NULL)
+ {
+ hrtf = LoadHrtf(device->Frequency);
+ if(hrtf == NULL) return ALC_FALSE;
}
*chans = DevFmtStereo;
*srate = hrtf->sampleRate;
+ return ALC_TRUE;
}
void FreeHrtfs(void)
diff --git a/Alc/hrtf.h b/Alc/hrtf.h
new file mode 100644
index 00000000..d9022d02
--- /dev/null
+++ b/Alc/hrtf.h
@@ -0,0 +1,28 @@
+#ifndef ALC_HRTF_H
+#define ALC_HRTF_H
+
+#include "AL/al.h"
+#include "AL/alc.h"
+
+enum DevFmtChannels;
+
+struct Hrtf;
+
+#define HRIR_BITS (7)
+#define HRIR_LENGTH (1<<HRIR_BITS)
+#define HRIR_MASK (HRIR_LENGTH-1)
+#define HRTFDELAY_BITS (20)
+#define HRTFDELAY_FRACONE (1<<HRTFDELAY_BITS)
+#define HRTFDELAY_MASK (HRTFDELAY_FRACONE-1)
+
+const struct Hrtf *GetHrtf(ALCdevice *device);
+ALCboolean FindHrtfFormat(const ALCdevice *device, enum DevFmtChannels *chans, ALCuint *srate);
+
+void FreeHrtfs(void);
+
+ALuint GetHrtfIrSize(const struct Hrtf *Hrtf);
+ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]);
+void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
+ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep);
+
+#endif /* ALC_HRTF_H */
diff --git a/Alc/hrtf_tables.inc b/Alc/hrtf_tables.inc
deleted file mode 100644
index 9c6af6a1..00000000
--- a/Alc/hrtf_tables.inc
+++ /dev/null
@@ -1,848 +0,0 @@
-/* Elevation metrics */
-static const ALubyte defaultAzCount[19] = { 1, 12, 24, 36, 45, 56, 60, 72, 72, 72, 72, 72, 60, 56, 45, 36, 24, 12, 1, };
-static const ALushort defaultEvOffset[19] = { 0, 1, 13, 37, 73, 118, 174, 234, 306, 378, 450, 522, 594, 654, 710, 755, 791, 815, 827, };
-
-/* HRIR Coefficients */
-static const ALshort defaultCoeffs[26496] =
-{
- +6117, +8354, +3531, +2903, +1118, +342, +874, -822, -2447, -1309, +579, -133, -617, -1093, -998, -416, -244, -202, -84, -134, -375, -200, -416, -331, -408, -614, -489, -332, -207, -97, -7, -145,
- +6958, +8678, +3013, +3274, +1145, +25, +847, -771, -2501, -1666, +534, +86, -597, -917, -967, -916, -367, -80, -198, -215, -475, -312, -442, -372, -399, -554, -517, -249, -103, -75, -5, -176,
- +6349, +8083, +2935, +2854, +1109, +344, +851, -891, -2351, -1252, +506, -191, -559, -861, -745, -485, -327, -77, -17, -172, -405, -189, -402, -350, -459, -599, -449, -315, -184, -77, +13, -134,
- +5910, +7494, +2698, +2625, +992, +373, +884, -825, -2197, -962, +698, -127, -425, -759, -697, -286, -213, -171, -64, -127, -336, -131, -355, -271, -368, -553, -428, -299, -179, -74, +4, -137,
- +5808, +7380, +2660, +2585, +1001, +453, +998, -698, -2078, -854, +773, -100, -470, -857, -730, -241, -185, -179, -63, -114, -325, -112, -322, -220, -300, -507, -404, -297, -216, -122, -35, -168,
- +5957, +7591, +2687, +2503, +871, +340, +913, -821, -2282, -1053, +775, -16, -459, -904, -784, -240, -114, -100, -12, -59, -285, -105, -334, -253, -340, -532, -400, -251, -127, -17, +33, -156,
- +6515, +8209, +2752, +2639, +892, +326, +895, -1074, -2683, -1313, +854, -53, -682, -1135, -939, -316, -155, -153, -32, -64, -346, -124, -339, -249, -345, -543, -400, -232, -129, -39, +38, -120,
- +6887, +8888, +3060, +2770, +926, +146, +833, -1245, -2800, -1317, +584, -231, -619, -1119, -983, -413, -244, -71, -9, -143, -405, -183, -399, -307, -420, -595, -439, -302, -153, -55, +34, -129,
- +7340, +9090, +2964, +3130, +1162, +115, +612, -1577, -2702, -692, +458, -1019, -864, -943, -587, -190, -434, -226, +41, -162, -398, -144, -463, -353, -533, -708, -464, -374, -270, -103, +2, -187,
- +8348, +9865, +2233, +2503, +594, +154, +1277, -1477, -3002, -433, +1280, -991, -1387, -1385, -643, +20, -514, -498, -16, -150, -545, -145, -486, -329, -539, -846, -509, -326, -250, -110, +9, -211,
- +8668, +10241, +2446, +2335, +160, +133, +1408, -1244, -3403, -895, +1742, -269, -1341, -2123, -1100, +207, -94, -571, -238, -198, -607, -211, -581, -326, -492, -792, -539, -293, -202, -119, -28, -265,
- +8261, +10052, +3261, +2775, +344, +65, +1000, -1138, -3661, -1615, +1337, +126, -290, -1970, -1899, -55, +143, -202, -175, -248, -492, -207, -591, -284, -495, -901, -578, -409, -197, -51, +38, -151,
- +7749, +9628, +3084, +3049, +870, +16, +727, -1159, -2880, -1819, +969, +83, -717, -1031, -1759, -1055, -39, -9, -26, -31, -379, -324, -646, -479, -344, -651, -608, -341, -196, -48, +22, -160,
- +7872, +8889, +2424, +3846, +1113, -405, +870, -636, -2562, -2175, +535, +438, -627, -691, -988, -1594, -378, +123, -383, -287, -574, -435, -436, -421, -370, -475, -575, -138, +9, -79, -10, -210,
- +7007, +8290, +2692, +3507, +1037, -125, +838, -876, -2265, -1597, +225, -49, -510, -580, -573, -987, -677, +32, +42, -236, -535, -281, -374, -349, -433, -522, -408, -257, -182, -133, +15, -132,
- +6475, +7694, +2419, +2913, +1152, +342, +794, -920, -2186, -1265, +352, -196, -457, -569, -494, -665, -413, +113, +33, -239, -428, -173, -379, -384, -517, -559, -408, -308, -159, -59, +31, -118,
- +5981, +7105, +2165, +2692, +1134, +347, +767, -876, -2030, -957, +421, -294, -318, -441, -466, -416, -281, -39, -27, -194, -378, -156, -345, -274, -384, -498, -440, -344, -158, -51, +21, -134,
- +5468, +6465, +2050, +2460, +952, +446, +858, -776, -1849, -646, +711, -106, -171, -377, -412, -225, -208, -139, -49, -122, -280, -59, -288, -217, -330, -482, -372, -276, -153, -54, +11, -123,
- +5247, +6086, +1760, +2189, +842, +506, +1054, -433, -1470, -298, +965, +30, -189, -498, -477, -163, -126, -106, -24, -94, -283, -72, -247, -143, -266, -434, -302, -196, -110, -68, -52, -213,
- +5232, +6232, +1996, +2383, +983, +625, +1098, -519, -1614, -432, +848, -66, -286, -585, -461, -110, -157, -165, -46, -92, -261, -20, -217, -109, -190, -394, -333, -281, -239, -151, -66, -182,
- +5323, +6297, +1900, +2226, +867, +582, +1114, -514, -1700, -507, +886, -53, -362, -695, -545, -42, +42, -2, +24, -89, -290, -90, -302, -188, -238, -341, -202, -173, -185, -163, -115, -218,
- +5574, +6674, +1997, +2183, +707, +407, +936, -776, -2047, -829, +914, +130, -285, -696, -573, -93, +9, -5, +50, +20, -186, -16, -247, -182, -271, -441, -315, -175, -47, +63, +58, -176,
- +6045, +7217, +2109, +2333, +722, +394, +912, -1008, -2484, -1201, +940, +97, -533, -929, -717, -112, +69, +18, +107, +96, -204, -31, -262, -175, -230, -397, -254, -106, -72, -21, +17, -112,
- +6856, +7935, +1962, +2469, +717, +365, +900, -1353, -2894, -1309, +1170, +26, -784, -1168, -861, -220, -61, -113, +16, +18, -323, -43, -253, -171, -282, -468, -311, -130, -56, +10, +78, -94,
- +7514, +8789, +1982, +2483, +712, +262, +907, -1695, -3191, -1325, +1153, -23, -806, -1333, -975, -279, -115, -59, -35, -42, -373, -130, -392, -273, -384, -542, -334, -150, -38, +4, +93, -104,
- +7708, +9393, +2471, +2673, +752, -59, +807, -1726, -3115, -1282, +555, -307, -586, -1146, -966, -429, -241, +103, +48, -175, -435, -160, -372, -287, -438, -565, -385, -281, -93, -15, +72, -115,
- +7961, +9595, +2700, +3173, +1089, -199, +393, -2045, -2982, -748, +119, -1067, -577, -787, -541, -413, -602, -36, +144, -149, -336, -111, -417, -324, -553, -659, -425, -410, -226, -58, +56, -137,
- +8750, +9725, +2189, +3527, +1193, -202, +307, -2424, -2793, +130, +87, -2091, -927, -659, -104, -33, -745, -205, +211, -231, -414, -73, -531, -374, -686, -789, -410, -438, -340, -94, +17, -238,
- +9887, +10729, +1149, +2712, +812, -159, +1171, -2374, -3238, +573, +900, -2331, -1559, -881, +10, +282, -825, -483, +230, -178, -567, -74, -569, -393, -734, -962, -410, -384, -393, -161, +71, -197,
- +11064, +11221, +279, +2282, +77, +57, +1829, -2384, -3518, +811, +1905, -2262, -2145, -1529, -99, +470, -985, -810, +158, -183, -755, -35, -580, -314, -703, -1105, -476, -311, -308, -116, +33, -294,
- +11675, +11698, +209, +1859, -553, +242, +2236, -2105, -4055, +456, +2775, -1639, -2377, -2493, -525, +885, -700, -1033, -74, -269, -767, -30, -730, -335, -644, -1070, -436, -206, -262, -87, -13, -377,
- +11801, +11992, +657, +1830, -875, +135, +2141, -1883, -4508, -144, +3105, -728, -2249, -3247, -939, +1040, -70, -1098, -336, -229, -882, -166, -780, -279, -597, -994, -559, -229, -208, -150, -49, -410,
- +11441, +12041, +1632, +2283, -957, -39, +1816, -1840, -4880, -918, +2879, +121, -1146, -3647, -1711, +1051, +438, -745, -603, -262, -776, -209, -700, -151, -609, -1078, -625, -402, -194, -201, -9, -262,
- +10865, +11676, +2584, +2613, -586, -83, +1224, -1524, -5125, -1724, +2382, +303, +58, -3199, -2831, +663, +561, -315, -300, -369, -601, -190, -808, -177, -617, -1246, -617, -484, -161, +7, +81, -166,
- +10191, +11218, +2753, +3225, -135, -314, +1139, -1492, -4741, -2381, +2120, +202, +83, -1978, -3635, -327, +757, +52, -23, -340, -548, -69, -879, -641, -441, -1126, -641, -329, -170, +77, +67, -175,
- +9689, +10846, +2307, +3298, +545, -344, +602, -1494, -3324, -2412, +1584, +308, -905, -920, -2772, -1685, +423, +196, -11, +88, -409, -493, -902, -608, -212, -710, -760, -321, -179, +12, +47, -183,
- +8953, +9908, +2218, +3607, +920, -373, +599, -1197, -2905, -2314, +1261, +665, -1096, -819, -1580, -2014, -168, +187, -326, -97, -344, -334, -636, -572, -272, -489, -771, -288, -106, -59, +97, -199,
- +8864, +8963, +1784, +4657, +969, -956, +982, -415, -2657, -2862, +633, +942, -750, -396, -1083, -2461, -216, +391, -668, -329, -673, -573, -389, -489, -318, -379, -677, +16, +122, -114, -18, -247,
- +7756, +8469, +2432, +4304, +831, -834, +867, -757, -2207, -2102, -12, +321, -466, -174, -519, -1837, -871, +255, +23, -250, -677, -423, -326, -339, -330, -413, -490, -195, -73, -162, -2, -152,
- +7061, +7757, +2298, +3660, +972, -50, +816, -871, -2023, -1762, +29, +39, -419, -270, -323, -1264, -738, +345, +74, -339, -535, -233, -317, -423, -530, -487, -350, -279, -220, -117, +68, -96,
- +6469, +7209, +2035, +3061, +1233, +321, +690, -887, -1952, -1381, +126, -112, -325, -222, -261, -975, -473, +378, +46, -334, -435, -156, -344, -439, -577, -492, -370, -312, -132, -41, +48, -98,
- +5924, +6587, +1791, +2840, +1306, +325, +630, -832, -1787, -1021, +168, -250, -169, -97, -250, -687, -289, +202, -37, -279, -361, -130, -348, -361, -448, -399, -386, -361, -133, -16, +50, -129,
- +5282, +6011, +1719, +2545, +1130, +445, +720, -784, -1642, -749, +308, -187, +39, -21, -232, -423, -260, +27, -35, -215, -317, -45, -205, -222, -390, -439, -388, -320, -115, -45, +11, -94,
- +4741, +5315, +1665, +2368, +986, +543, +781, -655, -1403, -392, +608, -36, +147, +49, -163, -239, -215, -100, -40, -117, -205, +8, -213, -171, -294, -397, -329, -264, -127, -36, +13, -103,
- +4473, +4913, +1415, +2018, +802, +585, +981, -314, -1070, -10, +964, +194, +186, -38, -233, -201, -159, -68, +40, -54, -215, -5, -156, -100, -249, -363, -242, -160, -67, -14, -33, -215,
- +4287, +4651, +1225, +2028, +1002, +772, +1151, -74, -767, +174, +960, +71, -57, -266, -220, -24, -57, -86, -63, -101, -197, +12, -123, -8, -137, -308, -225, -169, -123, -121, -128, -237,
- +4337, +4965, +1624, +2246, +1058, +843, +1155, -266, -1056, -75, +799, +3, -60, -285, -202, -30, -153, -156, -30, -66, -178, +71, -100, -2, -76, -278, -279, -283, -274, -184, -98, -187,
- +4443, +5025, +1531, +2119, +997, +856, +1205, -260, -1169, -213, +764, -10, -150, -366, -219, +89, +76, -16, -38, -108, -204, -23, -212, -56, -66, -154, -135, -246, -290, -240, -153, -192,
- +4604, +5187, +1421, +1877, +708, +663, +1129, -291, -1278, -255, +968, +170, -109, -537, -478, +41, +175, +171, +207, -3, -219, -11, -242, -189, -190, -256, -119, -13, -31, -100, -174, -309,
- +4923, +5652, +1529, +1902, +624, +528, +924, -671, -1743, -664, +996, +326, -100, -476, -372, +25, +128, +85, +100, +106, -73, +61, -152, -121, -199, -342, -237, -104, +32, +141, +70, -204,
- +5421, +6220, +1615, +2041, +613, +476, +868, -945, -2209, -1062, +1028, +282, -361, -678, -462, +90, +247, +119, +166, +124, -141, +83, -164, -99, -131, -291, -197, -34, +4, +4, +72, -42,
- +6190, +6818, +1507, +2236, +597, +518, +893, -1240, -2699, -1316, +1269, +222, -676, -957, -667, -54, +151, +26, +170, +185, -160, +80, -150, -125, -158, -266, -176, +4, -12, -12, +35, -111,
- +7121, +7541, +1201, +2394, +583, +455, +869, -1653, -3075, -1304, +1541, +95, -937, -1178, -764, -132, +36, -84, +64, +109, -308, +44, -155, -103, -220, -385, -224, -28, +7, +54, +114, -67,
- +7954, +8408, +983, +2438, +632, +359, +872, -2062, -3411, -1245, +1676, +31, -1048, -1363, -832, -150, -48, -120, +14, +94, -364, -58, -298, -170, -314, -457, -245, -56, +16, +70, +176, -53,
- +8426, +9277, +1223, +2430, +532, +133, +944, -2316, -3533, -1292, +1244, -43, -818, -1449, -1029, -259, -53, +135, -32, -56, -402, -136, -404, -282, -407, -503, -267, -114, +46, +41, +136, -109,
- +8583, +9860, +1762, +2634, +598, -282, +801, -2272, -3373, -1211, +481, -346, -524, -1183, -947, -470, -228, +324, +74, -228, -460, -132, -337, -273, -462, -518, -331, -270, -26, +19, +110, -100,
- +8789, +10123, +2143, +3154, +907, -539, +350, -2551, -3191, -653, -134, -1144, -348, -706, -562, -559, -647, +213, +190, -170, -308, -125, -412, -293, -550, -593, -367, -441, -161, -3, +111, -113,
- +9368, +10135, +1939, +3756, +1190, -650, -93, -2909, -2955, +75, -583, -2117, -371, -455, -4, -431, -1040, +118, +327, -275, -298, -31, -480, -340, -761, -730, -381, -524, -283, -44, +42, -215,
- +10370, +10210, +1204, +4156, +1175, -623, -28, -3363, -2672, +1145, -623, -3309, -728, -270, +428, +27, -1178, -99, +420, -357, -415, +13, -626, -389, -869, -847, -326, -533, -414, -65, +33, -301,
- +11635, +11075, -31, +3531, +952, -550, +724, -3443, -3032, +1791, +130, -3849, -1409, -370, +688, +391, -1323, -332, +504, -391, -598, +96, -680, -457, -950, -1002, -305, -479, -469, -136, +71, -286,
- +13207, +11905, -1547, +2772, +301, -274, +1873, -3587, -3556, +2285, +1234, -3973, -2188, -835, +809, +672, -1631, -769, +602, -241, -847, +83, -674, -374, -941, -1208, -342, -448, -473, -101, +134, -318,
- +14337, +12287, -2399, +2422, -469, +62, +2531, -3616, -3929, +2464, +2354, -3991, -2785, -1503, +623, +891, -1697, -1088, +457, -261, -1009, +151, -717, -276, -913, -1388, -372, -300, -384, -112, +67, -401,
- +15087, +12820, -2744, +1910, -1184, +425, +3120, -3448, -4563, +2187, +3466, -3489, -3173, -2589, +266, +1446, -1532, -1382, +191, -327, -1016, +193, -847, -301, -888, -1367, -296, -177, -336, -114, +20, -474,
- +15581, +13124, -2434, +1591, -1676, +521, +3195, -3036, -5227, +1724, +4250, -2658, -3404, -3573, -56, +1861, -986, -1649, +4, -355, -1041, +91, -1052, -239, -767, -1287, -362, -121, -296, -58, -65, -569,
- +15601, +13452, -1914, +1563, -2007, +399, +3052, -2823, -5735, +1036, +4617, -1613, -3294, -4431, -451, +2051, -245, -1777, -331, -235, -1215, -48, -1032, -173, -736, -1221, -537, -142, -232, -189, -69, -580,
- +15203, +13689, -870, +1955, -2244, +197, +2769, -2807, -6122, +172, +4587, -487, -2272, -5183, -1225, +2226, +446, -1489, -791, -175, -1171, -107, -880, -30, -790, -1309, -587, -320, -186, -316, -13, -442,
- +14648, +13594, +409, +2248, -2137, -16, +2270, -2431, -6673, -665, +4167, +189, -766, -5403, -2316, +2230, +741, -1027, -813, -342, -840, -164, -978, +109, -745, -1474, -642, -547, -154, -159, +47, -247,
- +13996, +13109, +1461, +2499, -1685, -37, +1524, -2013, -6863, -1546, +3712, +317, +445, -4840, -3714, +1807, +920, -566, -438, -485, -703, -148, -1075, +6, -791, -1647, -584, -567, -97, +72, +120, -190,
- +13165, +12534, +1976, +3362, -1471, -314, +1381, -1961, -6484, -2520, +3399, +361, +831, -3679, -5026, +938, +1344, -192, -237, -452, -597, -58, -1183, -507, -582, -1548, -641, -480, -68, +246, +63, -219,
- +12626, +12250, +1611, +3690, -681, -941, +1250, -1619, -5566, -2944, +3036, +177, +25, -1933, -5154, -665, +1470, +164, +107, -276, -664, -178, -1249, -762, -296, -1315, -631, -232, -234, +180, +66, -251,
- +11980, +11934, +1167, +3735, +109, -727, +510, -1829, -3781, -3108, +2485, +496, -1203, -728, -4093, -2241, +1182, +347, -49, +233, -470, -711, -1173, -711, -7, -812, -944, -259, -161, +83, +61, -212,
- +11247, +11010, +1120, +4114, +574, -764, +386, -1687, -3259, -2815, +2128, +825, -1544, -509, -2722, -2986, +467, +444, -350, +190, -276, -570, -1067, -700, +132, -512, -1156, -281, -35, -10, +123, -207,
- +10116, +9947, +1402, +4469, +759, -942, +664, -954, -2962, -3136, +1495, +1323, -1375, -529, -1640, -2951, +60, +455, -723, -188, -423, -428, -490, -651, -326, -390, -839, -121, -11, -87, +128, -262,
- +9934, +8876, +1128, +5737, +644, -1620, +1223, -109, -2816, -3751, +890, +1596, -1024, +3, -1280, -3531, +194, +690, -1086, -313, -780, -731, -285, -592, -233, -265, -834, +227, +227, -185, -20, -287,
- +8502, +8500, +2204, +5212, +430, -1605, +1028, -561, -2155, -2773, -185, +874, -495, +321, -570, -2903, -846, +586, -74, -234, -828, -571, -225, -357, -205, -310, -640, -115, +58, -204, -18, -162,
- +7584, +7772, +2171, +4547, +704, -725, +925, -716, -1861, -2401, -267, +505, -407, +183, -244, -2138, -927, +680, +60, -459, -671, -326, -222, -451, -469, -353, -358, -211, -203, -191, +84, -98,
- +6877, +7100, +2027, +3726, +1015, +37, +675, -791, -1748, -2003, -196, +244, -318, +111, -88, -1694, -708, +748, +20, -457, -485, -226, -270, -512, -629, -427, -353, -293, -167, -97, +74, -60,
- +6094, +6516, +1758, +3125, +1461, +313, +506, -750, -1620, -1508, -142, +48, -126, +224, -68, -1338, -382, +704, -7, -454, -398, -106, -300, -528, -626, -363, -337, -340, -80, +0, +68, -81,
- +5474, +5821, +1573, +2970, +1494, +257, +449, -672, -1419, -1123, -157, -119, +81, +343, -71, -994, -247, +423, -94, -356, -314, -117, -307, -403, -455, -271, -389, -398, -91, +12, +63, -119,
- +4706, +5219, +1556, +2650, +1342, +394, +527, -623, -1238, -816, -65, -106, +329, +424, -62, -677, -264, +193, -57, -276, -283, -47, -151, -234, -379, -329, -417, -360, -71, -27, +20, -78,
- +3969, +4463, +1642, +2395, +1176, +599, +584, -518, -1032, -470, +216, +31, +488, +473, -5, -409, -215, +23, -78, -181, -137, +68, -136, -185, -309, -316, -333, -291, -98, -38, +10, -54,
- +3424, +3827, +1536, +2086, +1002, +678, +738, -333, -681, +35, +605, +269, +533, +528, +71, -284, -241, -104, +39, -20, -139, +38, -65, -74, -225, -293, -257, -229, -78, +5, +12, -102,
- +3209, +3445, +1231, +1747, +899, +784, +1000, +168, -305, +345, +880, +396, +496, +306, -68, -218, -102, -1, +55, -36, -135, +45, -28, -19, -180, -238, -160, -103, -27, -22, -94, -255,
- +2989, +3191, +1074, +1836, +1186, +989, +1156, +381, -8, +502, +823, +223, +193, +66, +7, +5, -16, -56, -80, -81, -98, +68, +12, +88, -46, -191, -160, -138, -110, -149, -188, -250,
- +3027, +3528, +1478, +2058, +1276, +1085, +1144, +149, -311, +281, +686, +149, +146, +19, +50, +25, -119, -132, -55, -57, -69, +143, +32, +105, +37, -167, -229, -266, -280, -209, -151, -192,
- +3214, +3748, +1601, +2025, +1190, +1116, +1202, +89, -552, -87, +478, +220, +213, +9, +55, +81, -6, -61, -71, -93, -61, +81, -92, +76, +154, -10, -220, -365, -342, -251, -170, -159,
- +3266, +3741, +1347, +1791, +1078, +1077, +1224, +91, -623, +51, +737, +114, -29, -162, -63, +235, +299, +125, +20, -78, -150, -17, -140, -29, -21, +31, +66, -141, -296, -306, -239, -221,
- +3541, +4062, +1288, +1550, +718, +829, +1077, -44, -837, -142, +945, +448, +111, -311, -297, +101, +259, +279, +274, +70, -83, +51, -163, -131, -124, -170, -40, +66, +53, -44, -202, -351,
- +3954, +4589, +1351, +1593, +636, +691, +854, -482, -1382, -587, +1032, +601, +79, -242, -184, +108, +254, +168, +138, +202, +51, +122, -43, -74, -123, -230, -173, -35, +112, +219, +65, -237,
- +4535, +5212, +1390, +1740, +598, +607, +776, -814, -1908, -1025, +1099, +545, -214, -426, -239, +239, +413, +193, +207, +182, -47, +183, -57, -40, -30, -175, -148, +40, +73, +37, +118, +7,
- +5318, +5785, +1269, +1968, +575, +658, +805, -1127, -2442, -1307, +1372, +466, -591, -725, -443, +119, +395, +164, +270, +354, -56, +110, -69, -55, -25, -139, -51, +109, +11, +15, +19, -56,
- +6436, +6460, +882, +2236, +497, +666, +802, -1573, -2941, -1397, +1743, +286, -941, -976, -603, -18, +243, -4, +204, +282, -184, +170, -29, -57, -91, -187, -111, +112, +41, +27, +68, -96,
- +7585, +7281, +373, +2458, +491, +542, +790, -2104, -3319, -1286, +2043, +126, -1200, -1227, -664, -50, +85, -70, +93, +172, -322, +133, -69, -86, -185, -297, -168, +53, +66, +96, +196, +7,
- +8554, +8204, +13, +2518, +545, +433, +808, -2585, -3651, -1161, +2167, +23, -1301, -1412, -719, -73, +18, -111, +45, +202, -388, -7, -242, -122, -287, -383, -162, +38, +78, +115, +239, -27,
- +9212, +9220, +103, +2448, +407, +223, +921, -2981, -3805, -1200, +1719, +26, -1055, -1626, -929, -188, +43, +226, -94, +18, -406, -89, -400, -275, -396, -440, -171, +13, +140, +43, +175, -97,
- +9425, +9997, +611, +2554, +412, -263, +952, -2951, -3684, -1187, +857, -167, -621, -1410, -1053, -347, -65, +452, -3, -165, -453, -143, -340, -269, -451, -441, -242, -198, +101, +82, +181, -110,
- +9602, +10483, +1219, +2947, +590, -759, +563, -2991, -3446, -797, -98, -815, -218, -921, -768, -633, -444, +563, +104, -246, -350, -155, -369, -240, -521, -488, -298, -401, -10, +50, +144, -115,
- +9910, +10681, +1487, +3547, +923, -1024, +61, -3330, -3146, -137, -870, -1590, +8, -449, -298, -772, -939, +485, +312, -243, -240, -78, -399, -324, -669, -567, -332, -547, -156, +25, +160, -93,
- +10699, +10561, +1144, +4345, +1148, -1198, -465, -3692, -2804, +756, -1507, -2809, +121, -169, +369, -651, -1433, +435, +473, -418, -220, +23, -526, -346, -932, -715, -318, -648, -289, -5, +58, -250,
- +11865, +10458, +321, +5013, +1084, -1187, -415, -4235, -2391, +1999, -1758, -4266, -88, +147, +902, -193, -1705, +234, +619, -537, -297, +92, -743, -384, -1023, -815, -255, -684, -426, -12, +35, -330,
- +13346, +11005, -1112, +4810, +949, -1079, +138, -4587, -2456, +3025, -1295, -5300, -712, +202, +1270, +293, -1889, -46, +762, -642, -552, +226, -817, -466, -1180, -995, -171, -630, -552, -62, +74, -399,
- +14971, +12208, -3034, +3816, +594, -863, +1619, -4784, -3319, +3684, -109, -5706, -1550, +27, +1400, +652, -2108, -458, +869, -483, -776, +220, -858, -433, -1201, -1254, -117, -550, -640, -140, +204, -318,
- +16995, +12596, -4875, +3443, -244, -334, +2668, -5173, -3649, +4366, +1153, -6044, -2514, -559, +1728, +927, -2652, -901, +1093, -410, -1143, +329, -841, -335, -1196, -1458, -195, -525, -564, -33, +194, -462,
- +18241, +12894, -5826, +3138, -1130, +187, +3380, -5255, -4143, +4561, +2499, -6195, -3183, -1309, +1509, +1233, -2676, -1266, +894, -425, -1299, +432, -922, -204, -1176, -1686, -183, -313, -482, -86, +105, -535,
- +19257, +13367, -6379, +2592, -1984, +792, +4070, -5179, -4919, +4384, +3882, -5784, -3709, -2594, +1250, +1947, -2577, -1645, +617, -476, -1302, +491, -1070, -197, -1169, -1676, -76, -162, -446, -100, +47, -614,
- +19926, +13767, -6244, +2039, -2577, +1096, +4300, -4713, -5817, +3943, +5112, -5041, -4213, -3795, +981, +2627, -2147, -2070, +431, -519, -1281, +436, -1355, -148, -989, -1627, -104, -51, -433, -15, -50, -735,
- +20240, +14125, -5799, +1784, -3007, +1064, +4265, -4313, -6590, +3386, +5836, -3972, -4474, -4840, +741, +2976, -1373, -2410, +167, -416, -1413, +247, -1435, -24, -966, -1480, -291, -55, -313, -65, -145, -781,
- +20015, +14601, -5023, +1828, -3407, +908, +4058, -4144, -7140, +2450, +6274, -2630, -4153, -5964, +216, +3298, -453, -2534, -345, -178, -1641, +157, -1311, +64, -954, -1504, -457, -98, -260, -285, -55, -762,
- +19554, +14863, -3770, +2150, -3733, +724, +3709, -4072, -7621, +1495, +6312, -1303, -3056, -6981, -603, +3594, +321, -2274, -920, -58, -1568, +72, -1120, +198, -1037, -1588, -525, -300, -179, -434, +24, -584,
- +18917, +14814, -2183, +2351, -3715, +455, +3162, -3571, -8351, +569, +5938, -361, -1346, -7547, -1834, +3783, +700, -1769, -1070, -238, -1132, -62, -1211, +391, -1003, -1782, -585, -567, -111, -272, +77, -349,
- +18106, +14727, -945, +2225, -3047, +302, +2302, -2969, -8873, -290, +5489, -62, +243, -7348, -3434, +3665, +911, -1246, -777, -513, -915, -51, -1324, +362, -1049, -1967, -506, -762, +16, -24, +82, -173,
- +17254, +13805, +460, +2982, -2958, +154, +1644, -2479, -8779, -1643, +5145, +181, +1378, -6455, -5404, +3105, +1393, -741, -423, -612, -704, -72, -1484, +78, -955, -2125, -465, -626, +16, +278, +142, -257,
- +16265, +13474, +690, +3849, -2566, -357, +1746, -2519, -8172, -2680, +5031, +100, +1311, -4691, -6912, +1980, +2040, -358, -216, -622, -649, +103, -1622, -626, -497, -1964, -571, -423, -30, +370, +49, -249,
- +15646, +13159, +261, +4311, -1678, -1288, +1621, -1987, -7004, -3335, +4543, -14, +302, -2477, -7170, -48, +2406, +32, +137, -377, -773, -133, -1665, -841, -152, -1691, -589, -158, -270, +328, +50, -306,
- +14914, +12999, -328, +4365, -702, -1133, +553, -2016, -4671, -4043, +4026, +360, -1378, -617, -6226, -2166, +2377, +298, -4, +327, -691, -899, -1434, -845, +201, -1106, -1032, -122, -210, +203, +45, -267,
- +13958, +12124, -373, +4782, +21, -1129, +272, -2320, -3404, -3627, +3139, +1060, -2160, -3, -4519, -3752, +1820, +541, -476, +570, -311, -1038, -1434, -687, +457, -671, -1457, -167, -11, +62, +118, -218,
- +12918, +10973, -67, +5240, +257, -1386, +443, -1503, -3392, -3835, +2924, +1581, -2328, -20, -2956, -4208, +1045, +694, -894, +202, -292, -645, -959, -841, +200, -409, -1380, -60, +24, -53, +228, -310,
- +11453, +9857, +558, +5625, +370, -1608, +838, -661, -3107, -4122, +1928, +2028, -1762, -127, -1944, -4054, +595, +740, -1213, -166, -505, -568, -347, -773, -312, -278, -974, +83, +83, -136, +142, -319,
- +11087, +8602, +495, +7107, +58, -2371, +1638, +267, -3072, -4860, +1382, +2390, -1510, +558, -1623, -4806, +939, +963, -1665, -194, -913, -908, -115, -747, -101, -144, -1056, +521, +304, -293, -8, -330,
- +9334, +8472, +2057, +6324, -243, -2522, +1386, -290, -2159, -3680, -245, +1661, -676, +956, -788, -4263, -533, +965, -282, -154, -1031, -742, -56, -400, -21, -215, -885, +31, +223, -288, -38, -168,
- +8202, +7850, +2127, +5711, +161, -1682, +1271, -489, -1744, -3323, -499, +1254, -540, +771, -297, -3344, -963, +1117, -26, -591, -845, -454, -64, -490, -350, -197, -438, -86, -170, -321, +106, -106,
- +7291, +7027, +2168, +4730, +564, -540, +844, -580, -1481, -2901, -474, +853, -365, +616, -57, -2666, -805, +1195, -67, -613, -593, -252, -128, -623, -577, -254, -297, -288, -279, -138, +171, -54,
- +6561, +6470, +2014, +3851, +1081, +55, +479, -597, -1428, -2456, -448, +615, -253, +562, +94, -2318, -595, +1226, -130, -587, -411, -244, -197, -635, -712, -320, -371, -307, -113, -95, +84, -14,
- +5624, +5918, +1762, +3266, +1692, +206, +288, -499, -1267, -1883, -464, +389, +31, +706, +63, -1900, -243, +1098, -142, -584, -335, -87, -244, -648, -669, -209, -339, -372, -24, +17, +83, -55,
- +4953, +5180, +1625, +3144, +1769, +106, +214, -394, -1053, -1453, -538, +193, +277, +807, +43, -1499, -93, +748, -239, -450, -232, -115, -285, -525, -481, -91, -398, -447, -39, +45, +83, -112,
- +4115, +4607, +1619, +2888, +1682, +161, +244, -329, -812, -1141, -599, +67, +593, +924, +29, -1137, -210, +449, -129, -365, -249, -133, -121, -277, -340, -178, -530, -428, -2, -6, +39, -84,
- +3177, +4024, +1786, +2341, +1485, +534, +375, -316, -681, -795, -329, +287, +817, +880, +57, -781, -190, +258, -112, -286, -153, +95, +56, -236, -403, -237, -370, -335, -19, -47, -2, +10,
- +2412, +3137, +2012, +2211, +1367, +699, +342, -131, -395, -414, -56, +329, +935, +975, +138, -528, -171, +55, -126, -152, +41, +119, -74, -171, -229, -182, -327, -290, -76, -28, +10, -11,
- +1837, +2561, +1897, +1806, +1200, +798, +563, +60, +7, +156, +349, +604, +923, +1022, +216, -431, -239, -64, +75, +24, -47, +67, +76, -40, -176, -179, -231, -224, -40, +27, +0, -75,
- +1620, +2181, +1603, +1392, +1074, +916, +849, +620, +322, +470, +694, +763, +907, +764, +43, -376, -76, +71, +101, -3, -39, +86, +110, +0, -148, -121, -113, -69, +18, +9, -117, -268,
- +1298, +1691, +1267, +1399, +1307, +1124, +1131, +1104, +891, +667, +567, +575, +628, +507, +105, -108, +52, +24, -45, -25, -34, +55, +160, +131, -29, -57, -79, -54, -16, -156, -247, -286,
- +1179, +1848, +1466, +1730, +1760, +1293, +1046, +857, +729, +698, +565, +381, +236, +320, +318, +91, +9, -97, -187, -79, +91, +171, +186, +225, +142, -75, -156, -189, -210, -232, -263, -201,
- +1352, +2405, +2052, +1820, +1528, +1334, +1064, +583, +298, +292, +336, +420, +473, +384, +247, -41, -172, -129, -4, +7, +46, +224, +188, +178, +173, -32, -241, -326, -370, -251, -162, -160,
- +1579, +2518, +2005, +1719, +1482, +1383, +1139, +573, +88, -86, +163, +548, +481, +335, +281, +88, +49, -30, -101, -73, +80, +110, +12, +172, +343, +170, -228, -430, -393, -298, -216, -120,
- +1583, +2450, +1680, +1499, +1447, +1389, +1184, +570, +27, +164, +464, +283, +128, +199, +220, +325, +423, +123, -72, -74, -43, -22, -19, +72, +115, +277, +185, -229, -439, -410, -283, -162,
- +1893, +2685, +1508, +1157, +986, +1135, +1120, +583, -124, +57, +765, +643, +287, -137, -232, +275, +511, +407, +350, +8, -96, +73, -79, -165, +36, +100, +98, +172, -6, -229, -385, -374,
- +2209, +3190, +1517, +1044, +774, +938, +848, +161, -496, -290, +950, +973, +315, -37, -73, +18, +254, +388, +315, +238, +180, +91, -63, -33, -110, -192, -12, +129, +232, +155, -164, -407,
- +2814, +3765, +1508, +1224, +774, +836, +645, -346, -1219, -800, +1084, +985, +184, +33, +8, +229, +466, +169, +87, +354, +189, +192, +160, -56, +4, -65, -184, -15, +177, +366, +142, -203,
- +3495, +4412, +1460, +1383, +688, +753, +615, -665, -1708, -1197, +1222, +875, -213, -223, -72, +363, +610, +259, +273, +267, +37, +270, +44, +9, +100, -45, -90, +149, +122, +13, +149, +90,
- +4347, +4935, +1271, +1660, +643, +828, +646, -1007, -2278, -1449, +1567, +759, -633, -516, -277, +238, +622, +239, +355, +523, +20, +141, +46, -6, +111, -2, +46, +213, +21, +33, +1, +6,
- +5621, +5545, +799, +2031, +504, +892, +652, -1492, -2860, -1584, +2032, +530, -1030, -782, -469, +89, +432, +59, +340, +429, -61, +279, +83, -74, +47, +39, -51, +241, +56, -19, +59, -78,
- +6893, +6162, +149, +2382, +396, +828, +623, -2048, -3200, -1408, +2392, +211, -1344, -961, -526, -16, +350, -90, +203, +396, -312, +253, +114, +45, -53, -188, -37, +217, +87, +120, +108, -66,
- +8235, +7080, -573, +2693, +417, +618, +659, -2697, -3569, -1230, +2683, +76, -1575, -1280, -539, +24, +87, -57, +104, +215, -351, +233, +5, -119, -156, -194, -147, +124, +129, +137, +322, +117,
- +9244, +7992, -1030, +2743, +479, +517, +696, -3209, -3857, -1043, +2739, -57, -1623, -1427, -588, -20, +90, -120, +74, +343, -449, +31, -200, -78, -273, -310, -78, +136, +134, +157, +303, -20,
- +10028, +9088, -1078, +2631, +294, +324, +855, -3729, -3984, -1086, +2220, +48, -1346, -1774, -793, -139, +148, +326, -185, +119, -427, -45, -395, -273, -382, -360, -77, +135, +222, +28, +223, -85,
- +10294, +10035, -677, +2629, +250, -196, +1099, -3767, -3909, -1145, +1327, -1, -804, -1656, -1142, -169, +106, +562, -120, -57, -462, -169, -331, -270, -431, -351, -156, -128, +239, +131, +252, -134,
- +10483, +10682, -44, +2812, +332, -824, +879, -3596, -3635, -1021, +145, -213, -350, -1319, -899, -635, -133, +919, -37, -375, -472, -69, -227, -286, -527, -354, -246, -281, +155, +54, +190, -76,
- +10698, +11090, +572, +3361, +554, -1371, +356, -3757, -3360, -322, -956, -1204, +285, -664, -624, -896, -670, +916, +86, -272, -203, -223, -395, -193, -602, -435, -271, -578, +42, +87, +178, -136,
- +11106, +11176, +704, +4050, +883, -1630, -180, -4140, -2927, +390, -1871, -1878, +528, -231, -70, -1098, -1213, +889, +383, -352, -139, -56, -382, -365, -792, -502, -300, -681, -116, +59, +212, -78,
- +12036, +10896, +310, +5032, +1033, -1870, -823, -4447, -2503, +1349, -2741, -3214, +855, +29, +682, -1055, -1808, +920, +555, -599, -93, +53, -545, -351, -1135, -651, -258, -802, -256, +44, +72, -285,
- +13249, +10533, -420, +6055, +876, -1900, -821, -5027, -1957, +2680, -3299, -4856, +928, +484, +1323, -695, -2251, +831, +740, -767, -47, +126, -881, -350, -1161, -698, -223, -889, -359, +46, +17, -320,
- +14864, +10460, -1804, +6568, +665, -1731, -635, -5767, -1405, +4093, -3512, -6402, +622, +675, +1688, -26, -2440, +393, +956, -897, -408, +254, -945, -393, -1446, -932, -12, -855, -629, +79, +67, -544,
- +16627, +11397, -3842, +5964, +612, -1624, +440, -5965, -2042, +5011, -2485, -7307, -214, +766, +2141, +296, -2808, +260, +1140, -1052, -587, +505, -1093, -517, -1488, -1064, +12, -788, -651, -39, +118, -479,
- +18518, +12633, -6334, +4990, +229, -1244, +2367, -6506, -3133, +5859, -1129, -7799, -1129, +600, +2173, +719, -3075, -318, +1316, -740, -910, +425, -1093, -394, -1508, -1432, +145, -700, -804, -94, +327, -401,
- +20973, +12619, -8500, +4951, -770, -461, +3392, -7134, -3315, +6719, +196, -8369, -2213, +3, +2743, +961, -3843, -722, +1691, -730, -1369, +644, -1082, -293, -1519, -1634, +52, -689, -686, +59, +271, -608,
- +22297, +12836, -9690, +4807, -1655, +104, +4092, -7312, -3771, +7038, +1693, -8910, -3012, -482, +2558, +1188, -3919, -1129, +1548, -693, -1611, +794, -1184, -115, -1465, -1976, +34, -436, -598, -24, +171, -683,
- +23980, +12855, -10608, +4407, -2867, +1228, +4914, -7539, -4560, +7253, +3208, -8777, -3558, -1999, +2512, +1964, -3980, -1552, +1290, -765, -1611, +896, -1300, -1, -1603, -2008, +250, -237, -601, -60, +99, -743,
- +24531, +13684, -11034, +3704, -3405, +1665, +5463, -7291, -5568, +6806, +4893, -8341, -4325, -3233, +2310, +2880, -3885, -2013, +1022, -727, -1606, +925, -1552, -68, -1433, -1949, +261, -130, -552, -62, +43, -848,
- +25399, +13806, -10659, +3086, -4032, +2086, +5508, -6663, -6694, +6473, +6232, -7551, -4944, -4555, +2202, +3628, -3339, -2592, +933, -785, -1566, +810, -1901, +111, -1220, -1934, +196, +16, -580, +86, -113, -983,
- +25699, +14205, -10203, +2771, -4453, +2044, +5466, -6220, -7611, +5940, +7067, -6399, -5381, -5665, +2085, +3997, -2469, -3078, +674, -608, -1758, +594, -1930, +265, -1252, -1733, -62, +13, -409, -15, -218, -1005,
- +25576, +14678, -9511, +2627, -4889, +1979, +5231, -5940, -8313, +5036, +7731, -5018, -5437, -6902, +1757, +4371, -1482, -3465, +202, -277, -2109, +514, -1803, +302, -1201, -1716, -327, +65, -365, -277, -95, -1022,
- +24917, +15555, -8325, +2832, -5406, +1692, +5071, -5894, -8820, +3797, +8250, -3317, -4558, -8452, +986, +4981, -445, -3381, -624, +98, -2239, +474, -1567, +517, -1341, -1880, -275, -194, -234, -524, +73, -946,
- +24560, +15279, -6686, +3008, -5680, +1683, +4433, -5659, -9447, +3055, +7994, -2069, -3264, -9450, +188, +5223, +139, -3059, -1138, +123, -1936, +284, -1347, +532, -1421, -1864, -486, -372, -126, -624, +111, -613,
- +23630, +15485, -4781, +2918, -5523, +1209, +3879, -4787, -10506, +1989, +7668, -1020, -1165, -10262, -1408, +5686, +432, -2423, -1223, -173, -1294, +57, -1598, +885, -1360, -2222, -434, -735, -7, -301, +148, -390,
- +22705, +15510, -3489, +2520, -4580, +974, +2845, -3997, -11138, +1148, +7254, -749, +544, -10123, -3273, +5720, +656, -1873, -901, -539, -1078, +82, -1698, +797, -1433, -2392, -307, -961, +186, -54, +102, -179,
- +21833, +14435, -1480, +2989, -4502, +876, +1865, -3114, -11297, -386, +7023, -399, +2038, -9446, -5658, +5465, +1168, -1290, -470, -782, -783, -20, -1877, +659, -1411, -2696, -156, -783, +130, +317, +217, -316,
- +20537, +13992, -708, +4279, -4744, +442, +1972, -3237, -10625, -1985, +6923, -199, +2505, -7991, -7936, +4778, +2128, -1048, -448, -664, -657, +84, -2053, -179, -858, -2526, -357, -737, +238, +571, -51, -298,
- +19638, +14025, -1030, +4778, -3659, -452, +2274, -3224, -9891, -2808, +7103, -662, +1734, -5223, -9487, +3226, +2912, -583, -44, -906, -673, +388, -2239, -882, -152, -2483, -417, -219, -101, +496, +27, -274,
- +19049, +13570, -1555, +5415, -2800, -1809, +2085, -2243, -8328, -3763, +6265, -489, +380, -2622, -9535, +545, +3560, -254, +273, -392, -940, -193, -2156, -847, +103, -2093, -472, -40, -391, +519, -11, -393,
- +18168, +13590, -2249, +5443, -1644, -1455, +603, -2301, -5416, -4970, +5891, +62, -1742, -291, -8568, -1959, +3759, +29, -30, +506, -899, -1149, -1711, -913, +543, -1423, -1173, +54, -259, +333, +11, -312,
- +17035, +12827, -2281, +5894, -726, -1489, +185, -2933, -3444, -4639, +4541, +1190, -2977, +751, -6689, -4331, +3534, +367, -666, +1029, -430, -1560, -1739, -617, +856, -909, -1806, +43, +2, +135, +104, -229,
- +16109, +11603, -1857, +6452, -517, -1810, +245, -2043, -3755, -4481, +4547, +1368, -3096, +727, -4933, -5160, +2492, +733, -1012, +720, -307, -1028, -1535, -868, +957, -652, -2015, +138, +117, -22, +249, -321,
- +14557, +10522, -1242, +6803, -315, -2135, +723, -1118, -3548, -5279, +4014, +2629, -3572, +779, -3115, -5769, +2018, +890, -1739, +290, -311, -714, -642, -1091, +163, -204, -1599, +276, +13, -124, +387, -488,
- +12812, +9467, -224, +7139, -314, -2365, +1207, -230, -3341, -5355, +2557, +2879, -2315, +419, -2362, -5322, +1454, +982, -1883, -47, -628, -728, -93, -958, -294, -130, -1142, +362, +163, -228, +155, -376,
- +13067, +8369, -144, +8730, -2405, -3459, +1450, -1502, -5332, -4279, +6473, +1714, -1900, +3709, -1903, -4707, +1918, +120, -2550, -1093, -1848, -621, -724, -1598, -147, -744, -877, +540, -151, -509, +318, -28,
- +10904, +8241, +866, +7747, -891, -4073, +130, -1350, -3923, -2891, +4427, +2115, -885, +2373, -1299, -4343, +153, +77, -1658, -317, -1588, -605, +53, -1825, -85, -335, -1528, -11, -42, -273, +59, -76,
- +9279, +7452, +1520, +7064, -405, -3081, +178, -1385, -2926, -2332, +3123, +1898, -776, +1781, -925, -3718, -102, -120, -1233, -82, -1199, -290, +2, -1550, -49, -380, -1428, -264, -245, -270, +11, -162,
- +7668, +6712, +2160, +6267, +54, -2125, +134, -1110, -2049, -2036, +2189, +1460, -699, +1339, -688, -3011, -497, -119, -970, -142, -497, +186, +37, -1292, -184, -526, -1267, -503, -546, -437, +10, -9,
- +6368, +6134, +2492, +5439, +623, -1515, +73, -449, -1505, -1848, +1544, +1044, -644, +955, -348, -2562, -737, -6, -786, +148, +175, +380, -63, -1068, -366, -637, -1119, -714, -616, -443, -44, +1,
- +5309, +5691, +2463, +4700, +1132, -1190, +301, +59, -1194, -1566, +901, +654, -559, +719, -197, -2168, -766, +93, -248, +496, +263, +194, -53, -903, -530, -692, -1037, -585, -576, -463, -126, -99,
- +4671, +5240, +2273, +4089, +1224, -820, +599, +183, -902, -1333, +289, +350, -412, +640, -190, -1832, -504, +307, +145, +562, +47, +10, -140, -891, -579, -467, -751, -658, -629, -412, -121, -71,
- +4304, +4612, +2145, +3630, +1141, -235, +799, +247, -609, -1181, -104, +233, -152, +634, +32, -1399, -325, +524, +389, +368, -139, -41, -258, -648, -199, -313, -764, -659, -480, -282, -35, +38,
- +3883, +4121, +1999, +3085, +1218, +245, +812, +308, -391, -1122, -309, +165, +293, +913, +46, -1198, -224, +714, +439, +55, -298, +56, +12, -400, -192, -282, -674, -589, -276, -72, +113, +77,
- +3262, +3880, +1810, +2399, +1483, +674, +763, +273, -288, -1047, -181, +700, +489, +675, +71, -953, -158, +742, +296, -120, -45, +156, +92, -270, -319, -271, -421, -326, -57, +99, -64, -314,
- +2385, +3308, +1933, +2191, +1681, +725, +640, +373, +136, -286, -143, +637, +683, +410, +103, -565, -257, +619, +421, -40, +28, +179, +55, -233, -135, -54, -204, -72, -29, -217, -320, -330,
- +1874, +3072, +1941, +1419, +1419, +1279, +891, +484, +398, +297, +230, +463, +469, +136, +85, -228, -107, +538, +410, +40, -27, +98, +145, +77, +20, +54, +21, -272, -370, -309, -248, -206,
- +1591, +2376, +1629, +1368, +1569, +1437, +1231, +1006, +583, +432, +297, +204, +299, +145, -140, +13, +312, +339, +220, +17, +14, +285, +382, +203, +101, -101, -334, -332, -302, -287, -184, -195,
- +1470, +1787, +1502, +1987, +1911, +1545, +1043, +878, +865, +431, +197, +86, +12, +101, +92, +101, +251, +178, +190, +346, +300, +250, +251, +133, -107, -287, -400, -336, -238, -260, -239, -257,
- +1914, +2455, +1662, +1958, +1844, +1522, +942, +380, +248, +262, +332, +128, +22, +126, +219, +6, -12, +304, +516, +586, +402, +88, -170, -256, -295, -306, -261, -267, -279, -273, -326, -327,
- +1650, +2454, +1992, +2081, +1838, +1445, +722, +274, +244, +203, +344, +372, +259, +83, -81, -61, +209, +336, +515, +666, +466, +145, -229, -453, -374, -308, -238, -216, -280, -231, -312, -373,
- +1972, +2726, +1615, +1875, +1444, +1065, +882, +237, +52, +429, +512, +299, +333, -155, -232, +94, +178, +234, +473, +659, +391, +136, -262, -514, -398, -381, -424, -222, -224, -324, -266, -374,
- +1944, +2569, +1405, +1599, +1309, +1157, +866, +373, +250, +451, +528, +453, +471, +1, +55, +191, +129, +155, +283, +436, +597, +713, +68, -320, -396, -509, -294, -216, -242, -220, -186, -273,
- +2213, +2847, +1259, +1256, +996, +980, +849, +260, -32, +445, +818, +478, +247, +265, +193, +76, +464, +202, +102, +347, +222, +450, +618, +397, -308, -565, -442, -327, -186, -168, -163, -249,
- +2697, +3456, +1227, +1213, +572, +517, +850, +102, -387, +192, +924, +490, +415, +251, -28, +334, +487, +237, +455, +306, -44, +361, +407, +349, +369, -96, -484, -382, -224, -207, -148, -176,
- +3120, +3716, +1221, +1448, +755, +624, +603, -564, -1136, +136, +1257, +246, +285, +171, -38, +383, +232, +372, +711, +324, +99, +204, -9, +285, +321, +68, +177, -36, -413, -443, -150, -173,
- +3790, +4330, +1096, +1569, +784, +588, +463, -1059, -1653, +106, +1501, +73, -126, -239, -105, +460, +435, +368, +402, +389, +91, +309, +250, +37, -30, -24, +199, +248, +66, -210, -381, -373,
- +4622, +5180, +929, +1541, +623, +502, +584, -1498, -2233, +215, +1742, -187, -310, -505, -413, +362, +388, +344, +575, +292, -268, +436, +270, +95, +161, -323, -90, +279, +151, -2, +128, -96,
- +5681, +5925, +575, +1587, +609, +492, +477, -2071, -2626, +569, +1878, -446, -437, -854, -523, +332, +170, +294, +523, +68, -219, +380, -38, +251, +114, -335, +23, -101, -23, +248, +375, +75,
- +6767, +6666, +205, +1705, +662, +498, +302, -2825, -2958, +1150, +2042, -710, -533, -1232, -642, +377, +122, +237, +348, -95, -351, +388, -30, +5, -60, -377, -119, +125, +76, -40, +330, +247,
- +7914, +7510, -124, +1761, +488, +420, +174, -3558, -3104, +1640, +2028, -832, -567, -1607, -766, +361, +95, +311, +212, -352, -461, +375, -113, -24, -351, -633, -128, +128, +9, -5, +457, +80,
- +8830, +8494, -246, +1750, +304, +130, +113, -4143, -3165, +1945, +1825, -857, -549, -1777, -958, +191, +133, +387, +88, -480, -608, +386, -265, -246, -302, -723, -280, -84, -50, +74, +350, +96,
- +9314, +9665, +71, +1635, +346, -372, -34, -4328, -3176, +2030, +1536, -817, -547, -1732, -1016, -133, +66, +591, +24, -506, -733, +116, -40, -327, -495, -730, -460, +25, -137, -166, +374, -5,
- +9168, +10764, +1097, +1383, +468, -796, -470, -4274, -3169, +1769, +1273, -725, -691, -1625, -1027, -452, -36, +630, +83, -652, -832, +127, -43, -349, -695, -737, -514, -168, -181, -314, +338, +138,
- +8846, +11350, +2560, +1552, +433, -953, -869, -4243, -3192, +1361, +998, -476, -837, -1626, -886, -800, -125, +635, -124, -228, -816, -255, -7, -394, -552, -761, -755, -414, -246, -133, +444, +75,
- +8964, +11306, +3527, +2438, +253, -982, -961, -4230, -3082, +755, +442, -71, -869, -1742, -700, -1038, -454, +793, +25, -389, -604, -243, +7, -464, -738, -765, -951, -330, -59, -171, +251, +95,
- +9403, +11033, +3733, +3695, +308, -1271, -992, -4163, -2722, +92, -735, +217, -696, -1699, -422, -1673, -402, +984, -229, -198, -530, -373, +28, -463, -956, -681, -906, -518, -289, -162, +497, +102,
- +10184, +10713, +3388, +4822, +577, -1450, -980, -3974, -2096, -266, -2455, +170, -229, -2033, +139, -1657, -867, +1176, -218, -154, -435, -585, +36, -392, -1039, -506, -950, -753, -269, -164, +336, -63,
- +11469, +10305, +2546, +5881, +499, -1455, -857, -3843, -1101, -509, -4401, -50, +59, -2342, +782, -1732, -924, +1406, -569, -258, -144, -530, -49, -395, -1238, -446, -756, -782, -536, -315, +337, -105,
- +12812, +9997, +1333, +7068, +255, -1649, -308, -3676, +7, -196, -6478, -1003, +993, -2770, +1003, -1205, -1230, +1463, -713, -345, +195, -392, -236, -389, -1244, -431, -777, -964, -608, -183, +371, -471,
- +14298, +10024, -465, +8212, +114, -2512, +382, -3674, +1378, +663, -8685, -2459, +1859, -2562, +871, -988, -1367, +1466, -684, -580, +254, -110, -241, -347, -1398, -758, -715, -816, -729, -361, +154, -579,
- +15791, +10811, -2667, +8435, +624, -3271, +1069, -3748, +2502, +2079, -10027, -4329, +2301, -1901, +666, -578, -1480, +1296, -627, -770, +123, +401, -53, -652, -1473, -822, -551, -788, -1234, -414, +540, -655,
- +17964, +11856, -5206, +7310, +1001, -3366, +1912, -4139, +2658, +3650, -10394, -6002, +1938, -1051, +777, -287, -1664, +896, -566, -1001, +87, +651, -41, -918, -1419, -920, -813, -755, -1256, -323, +672, -811,
- +20009, +12521, -7253, +6282, +961, -3398, +2583, -4837, +2731, +5771, -10940, -7407, +1508, -472, +1186, -388, -1734, +332, -519, -1043, -71, +553, -29, -952, -1661, -1165, -989, -425, -1171, -377, +657, -839,
- +22177, +13864, -9457, +4361, +273, -2050, +3806, -6178, +2512, +7329, -10722, -7725, +990, -611, +1552, -139, -1889, -63, -466, -1163, -297, +596, -38, -1172, -1902, -1306, -955, -76, -1070, -458, +771, -742,
- +24345, +14808, -11064, +2917, -761, -281, +4365, -7368, +2909, +8263, -9604, -7789, +243, -1094, +2044, +574, -2131, -536, -396, -1094, -498, +632, -243, -1137, -1962, -1496, -848, +190, -940, -375, +1054, -832,
- +26147, +15550, -12303, +1685, -1810, +967, +4288, -7960, +2974, +9042, -8220, -8190, -317, -1893, +2641, +1163, -2716, -789, -273, -1142, -847, +531, -446, -868, -2137, -1852, -734, +364, -774, -243, +1065, -1025,
- +27659, +16152, -13062, +755, -2711, +1616, +4052, -7901, +2526, +9678, -6491, -8602, -661, -2830, +3049, +1720, -3198, -833, -91, -1450, -1161, +618, -586, -618, -2344, -2144, -611, +510, -566, -204, +872, -1008,
- +28303, +17220, -13451, +40, -3448, +1563, +3863, -7612, +1462, +10219, -4267, -9081, -1078, -3763, +2992, +2435, -3478, -882, -13, -1844, -1413, +823, -875, -471, -2328, -2410, -559, +601, -471, -315, +732, -991,
- +29181, +17405, -13114, -304, -4240, +1458, +3452, -7492, +539, +10765, -2404, -8991, -1702, -4595, +2982, +2817, -3292, -1057, +74, -2172, -1478, +872, -1165, -289, -2195, -2469, -548, +634, -663, -287, +578, -1042,
- +29321, +17827, -12348, -557, -5122, +1071, +3363, -7877, -467, +11248, -887, -8472, -2373, -5291, +2598, +3058, -2743, -1532, +107, -2142, -1752, +699, -1290, -111, -1997, -2388, -740, +468, -816, -385, +487, -985,
- +28805, +18575, -11075, -519, -6256, +621, +3883, -8757, -1416, +11447, +404, -7310, -2751, -5966, +1821, +3238, -1902, -1967, -52, -1838, -2084, +568, -1247, +63, -1562, -2577, -1051, +401, -1056, -280, +613, -1053,
- +27710, +19425, -9278, -279, -7398, +89, +4632, -9740, -2488, +11491, +1418, -5692, -2452, -7072, +956, +3436, -1270, -1977, -465, -1644, -2124, +549, -1018, +267, -1537, -2600, -1365, +17, -689, -160, +642, -1022,
- +26524, +19729, -7061, +31, -8340, -267, +5003, -10177, -3987, +11429, +2435, -4362, -1321, -8478, +66, +3718, -1132, -1735, -895, -1806, -1690, +886, -1190, +400, -1479, -2883, -1377, -121, -394, -59, +689, -900,
- +24731, +20271, -4631, +239, -8724, -1229, +4844, -9185, -6220, +10730, +4243, -3815, +672, -9539, -1506, +4100, -1430, -1335, -947, -2166, -1162, +1047, -1494, +767, -1758, -3042, -837, -474, -154, +165, +571, -941,
- +23477, +19815, -2244, +479, -9027, -1898, +3618, -7399, -7878, +9201, +6108, -3552, +2583, -9590, -3747, +4198, -1760, -1193, -323, -2539, -1400, +1397, -1635, +542, -1400, -3228, -438, -316, -265, +162, +498, -845,
- +22603, +18971, -668, +1272, -8642, -2638, +2333, -6179, -8347, +7433, +7800, -2940, +3459, -8248, -6239, +4034, -1687, -1398, +219, -2550, -1401, +1181, -1707, +569, -817, -3297, +15, -296, -506, +401, +364, -924,
- +21958, +18536, -765, +2387, -7488, -4223, +1716, -5274, -8935, +6110, +9409, -2450, +3540, -6393, -8448, +3758, -1179, -2277, +576, -2418, -1529, +1177, -1880, +420, +14, -3051, -213, -188, -381, +229, +231, -793,
- +22176, +17185, -1463, +4151, -7417, -5322, +1894, -4670, -9301, +4733, +10404, -1838, +3744, -5092, -9471, +2688, -467, -2307, -46, -2508, -1717, +1645, -1714, +18, +585, -2841, -290, -132, -583, +271, +215, -863,
- +21283, +15947, -1061, +5846, -8289, -5644, +2856, -4640, -8855, +2098, +10641, -385, +3529, -2820, -10460, +1131, +531, -2119, -590, -2947, -2184, +2054, -1090, -387, +1198, -3026, -869, +546, -650, +116, +60, -894,
- +19683, +14620, -396, +7001, -7790, -5818, +2880, -3841, -8800, -338, +10153, +959, +3167, -585, -10098, -824, +1447, -2278, -872, -2755, -2996, +1653, -697, +272, +1462, -3849, -1195, +1382, -669, -246, -11, -701,
- +19043, +12870, -2025, +8715, -5341, -5810, +2282, -4136, -8408, -1971, +10181, +1931, +1229, +1395, -8274, -2327, +1832, -1907, -1520, -2677, -3203, +831, -255, +370, +1503, -3747, -1696, +1786, -499, -464, -64, -480,
- +17772, +11494, -1905, +9490, -4457, -5781, +2323, -3030, -7953, -3525, +9683, +2138, -957, +3838, -5603, -4565, +2549, -1532, -2419, -1808, -2980, +12, -610, -213, +1746, -2508, -2211, +1172, +20, -342, -24, -448,
- +16172, +10332, -1197, +9288, -3999, -4949, +1874, -2282, -7098, -4475, +8985, +1667, -1887, +4717, -3907, -5051, +2520, -1200, -2844, -1330, -2611, -280, -1072, -1112, +1423, -1375, -1811, +550, -258, -177, +416, -403,
- +14861, +9191, -894, +9322, -3451, -4203, +1793, -2119, -6076, -4508, +7671, +1778, -2043, +4285, -2907, -4648, +2360, -879, -2603, -1241, -2298, -406, -1008, -1513, +521, -984, -1055, +584, -582, -325, +664, -263,
- +15154, +9134, -4908, +9650, +694, -5568, -98, -860, -5127, -4048, +7837, -470, -3638, +3508, -972, -2437, +3394, +805, -1417, +31, -1653, -577, -2362, -2979, -580, -1077, -1684, -192, -259, +22, +565, -429,
- +12672, +9048, -2546, +8370, +349, -5006, +73, -1080, -4272, -3672, +5900, +444, -2326, +2893, -1066, -2332, +2479, +666, -949, -82, -1657, -457, -1794, -2452, -454, -1165, -1497, -205, -372, -240, +406, -163,
- +10640, +8312, -1031, +7498, +500, -3857, +463, -1057, -3977, -3222, +4691, +603, -1571, +2325, -824, -2114, +1780, +754, -897, -192, -1342, -620, -1307, -1779, -405, -857, -1348, -343, -250, -417, +44, -237,
- +8848, +7462, +273, +6812, +521, -2799, +1008, -1064, -3777, -2718, +3754, +821, -1252, +1806, -375, -2145, +1225, +906, -817, -265, -1155, -585, -1036, -1174, -21, -762, -1257, -311, -233, -510, -203, -397,
- +7576, +6767, +783, +6094, +949, -1930, +961, -934, -3200, -2533, +3115, +1137, -1365, +1382, -102, -2040, +908, +789, -690, -334, -1018, -480, -555, -707, -43, -640, -1047, -255, -386, -684, -317, -445,
- +6758, +6214, +818, +5337, +1627, -1135, +432, -710, -2305, -2322, +2540, +1251, -1296, +892, -62, -1566, +663, +551, -577, -337, -682, -77, -179, -659, -184, -409, -797, -413, -574, -679, -216, -506,
- +5676, +5613, +1210, +4774, +1859, -559, +347, -565, -1759, -1969, +1960, +1004, -1099, +525, -53, -1205, +350, +369, -435, -6, -319, -23, -94, -656, -285, -373, -741, -563, -562, -531, -260, -514,
- +4838, +5040, +1571, +4251, +1972, -105, +267, -310, -1227, -1573, +1267, +789, -798, +205, +14, -944, +147, +508, -9, +9, -221, +150, -128, -742, -391, -376, -652, -447, -470, -469, -201, -405,
- +3971, +4513, +1934, +3945, +1836, +92, +581, -63, -938, -1357, +811, +579, -793, +202, +181, -781, +327, +624, -92, +15, +0, +147, -352, -881, -357, -191, -505, -444, -412, -282, -88, -284,
- +3487, +4143, +1924, +3589, +1775, +195, +713, +196, -635, -1287, +387, +393, -687, +361, +568, -535, +98, +502, -1, +100, +31, -150, -611, -593, -111, -190, -456, -382, -216, -81, -181, -553,
- +3301, +3728, +1795, +3379, +1523, +332, +960, +396, -543, -1253, +191, +235, -129, +880, +351, -652, +117, +445, +130, +39, -216, -238, -343, -293, -61, -146, -363, -182, -162, -325, -424, -636,
- +3158, +3429, +1574, +3069, +1415, +510, +1197, +428, -494, -1109, +222, +719, +168, +681, +275, -640, +81, +477, +19, -67, -36, -85, -122, -162, +45, -5, -361, -356, -380, -419, -409, -428,
- +2927, +3070, +1345, +2819, +1417, +712, +1293, +444, -262, -476, +280, +510, +400, +568, +118, -618, -112, +442, +241, +165, -34, -72, +77, +111, +94, -334, -675, -432, -303, -274, -306, -497,
- +2770, +2981, +1085, +2080, +1492, +1281, +1415, +707, +136, -480, +296, +711, +259, +268, -123, -614, +243, +742, +216, +47, +81, +319, +285, -194, -408, -500, -506, -280, -185, -330, -423, -456,
- +2145, +2721, +1165, +1872, +1627, +1355, +2019, +1188, +250, -296, -84, +490, +282, +67, -115, -178, +405, +756, +354, +121, +267, +315, -30, -468, -422, -383, -385, -212, -269, -357, -406, -427,
- +1842, +2681, +1515, +1848, +2108, +1608, +1340, +1172, +512, -174, -238, -168, -13, +491, +474, +113, +382, +613, +415, +165, +91, -47, -298, -384, -349, -382, -402, -278, -199, -319, -431, -344,
- +1494, +2675, +2068, +1863, +2114, +2048, +1472, +644, +14, -248, -149, +107, +179, +299, +556, +612, +502, +443, +238, -13, -145, -180, -250, -339, -297, -336, -446, -377, -225, -244, -239, -265,
- +1925, +2822, +1707, +2248, +2162, +1532, +1572, +666, -432, -363, +210, +212, +263, +498, +470, +699, +813, +253, -219, -217, -141, -158, -176, -306, -384, -385, -364, -200, -281, -326, -188, -200,
- +1895, +2793, +1934, +2045, +1846, +1354, +1196, +799, +59, -3, +248, +165, +197, +407, +651, +831, +698, +67, -242, -221, -251, -169, -144, -186, -354, -464, -369, -235, -233, -217, -227, -253,
- +2070, +3085, +1525, +1328, +1530, +1219, +1048, +1205, +562, -2, +387, +198, +130, +544, +658, +484, +722, +457, -348, -457, -175, -78, -253, -223, -258, -370, -406, -378, -222, -139, -199, -290,
- +2157, +2952, +1156, +902, +1034, +1185, +1499, +1126, +501, +624, +479, -49, +331, +597, +587, +621, +629, +548, +175, -291, -470, -235, -85, -52, -278, -368, -303, -369, -323, -238, -97, -173,
- +2202, +2907, +1140, +947, +996, +914, +968, +769, +506, +769, +808, +471, +171, +297, +838, +683, +510, +567, +580, +137, -151, -326, -508, -27, -10, -284, -285, -236, -358, -292, -161, -179,
- +2228, +3053, +1096, +862, +1274, +1155, +755, +13, -357, +880, +1376, +402, +198, +406, +514, +671, +748, +486, +514, +663, +288, -200, -289, -329, -436, -55, -28, -272, -239, -283, -290, -193,
- +2611, +3293, +974, +955, +1269, +1230, +755, -497, -748, +618, +1056, +494, +365, +41, +465, +810, +420, +494, +736, +416, +453, +551, -173, -405, -427, -456, -169, -36, -153, -282, -273, -363,
- +3071, +3880, +1049, +902, +1063, +1099, +721, -721, -1094, +709, +1109, -47, +104, +119, +412, +545, +413, +580, +520, +543, +532, +362, +329, +140, -499, -431, -240, -372, -190, -30, -169, -356,
- +3643, +4399, +965, +972, +1042, +1109, +628, -1277, -1336, +964, +1149, -203, -182, -383, +345, +664, +317, +410, +437, +373, +394, +662, +276, +180, +133, -200, -383, -376, -281, -286, -117, -162,
- +4308, +4895, +774, +1151, +1170, +1121, +455, -1795, -1513, +1267, +1131, -396, -245, -566, +93, +375, +376, +540, +286, +94, +297, +541, +252, +439, +34, +129, +201, -368, -356, -264, -280, -354,
- +5087, +5494, +565, +1262, +1166, +1002, +246, -2296, -1418, +1649, +899, -695, -391, -688, +139, +229, +44, +521, +312, -3, +101, +250, +192, +280, +43, +280, +150, +88, +29, -357, -310, -372,
- +5947, +6051, +327, +1497, +1239, +800, -127, -2807, -1134, +2147, +640, -918, -589, -888, +220, +107, +62, +477, +59, -49, +73, +198, -35, +79, -132, +175, +309, +137, +146, +162, -75, -593,
- +6826, +6642, +77, +1786, +1321, +527, -620, -3298, -663, +2560, +320, -1067, -693, -1064, +226, -95, -6, +673, -51, -262, -29, +141, -44, -11, -506, +62, +205, +6, +401, +111, +23, -56,
- +7619, +7443, -127, +1929, +1356, +155, -1099, -3708, -137, +2846, -83, -1160, -806, -1101, +269, -385, -138, +769, -105, -266, -156, -64, -45, -101, -607, -105, -82, +19, +101, +44, +338, -87,
- +8308, +8291, -181, +1996, +1443, -217, -1606, -4093, +424, +3041, -446, -1225, -972, -1051, +348, -589, -310, +757, -179, -230, -151, -213, -150, -169, -724, -105, -113, -531, +38, +251, +144, +14,
- +8643, +9273, +110, +1817, +1665, -587, -2048, -4412, +705, +3223, -686, -1244, -1233, -1013, +428, -696, -381, +630, -323, -238, -129, -251, -193, -373, -663, -295, -481, -278, -3, -42, +123, -69,
- +8492, +10281, +986, +1409, +1924, -770, -2443, -4558, +552, +3340, -711, -1234, -1461, -1100, +472, -719, -429, +587, -437, -400, -100, -332, -135, -347, -1076, -422, -280, -435, -79, -23, +2, -146,
- +8125, +10926, +2345, +1150, +1899, -669, -2844, -4563, +156, +3228, -595, -1223, -1573, -1303, +463, -750, -482, +579, -448, -544, -287, -237, -139, -775, -987, -370, -466, -463, -189, -20, +78, -37,
- +7991, +11060, +3529, +1603, +1541, -533, -3046, -4622, -35, +2877, -564, -1180, -1626, -1431, +402, -852, -505, +583, -405, -609, -263, -542, -401, -426, -1162, -560, -503, -504, -197, +50, +140, -226,
- +8113, +10987, +4130, +2562, +1381, -747, -2977, -4641, -186, +2488, -599, -1166, -1769, -1438, +351, -1006, -539, +563, -351, -314, -744, -723, -154, -612, -1117, -726, -662, -455, -57, +40, -92, -256,
- +8541, +10760, +4178, +3497, +1698, -1029, -2982, -4222, -351, +1963, -668, -970, -2110, -1515, +400, -1246, -614, +645, -262, -603, -476, -696, -449, -571, -1094, -668, -849, -390, -123, -169, +68, -29,
- +9463, +10347, +3864, +4361, +1905, -1015, -3375, -3543, -178, +968, -787, -513, -2341, -1829, +501, -1686, -325, +497, -681, +38, -559, -871, -367, -691, -1137, -482, -872, -677, -284, +7, +225, -241,
- +10674, +9874, +3106, +5362, +1727, -766, -3609, -3015, +543, -431, -1222, +153, -2336, -2209, +365, -1836, -554, +242, -426, +197, -633, -802, -399, -696, -1174, -325, -1145, -803, -31, -108, -43, -199,
- +11979, +9620, +1869, +6561, +1461, -835, -3245, -2641, +1610, -1691, -2279, +974, -2010, -2575, +505, -2638, -686, +670, -1065, +774, -478, -978, -319, -585, -1119, -498, -1130, -708, -19, -296, -40, -290,
- +13201, +9744, +157, +7624, +1518, -1581, -2587, -2110, +2716, -2532, -3960, +1424, -1264, -2535, -109, -3054, -615, +404, -1230, +1095, -263, -1158, -337, -435, -1109, -466, -1189, -812, +84, -300, -171, -443,
- +14767, +10074, -1860, +8018, +1956, -2430, -2103, -1372, +3819, -2797, -5967, +1234, +173, -2924, -421, -3162, -1160, +752, -1619, +1210, +95, -1349, -306, -444, -1114, -283, -1142, -1053, +276, -314, -302, -597,
- +16745, +11407, -4630, +6674, +3018, -2190, -1545, -1323, +4470, -2021, -7769, +629, +1347, -2958, -574, -3466, -1241, +900, -1709, +1083, +268, -1132, -420, -544, -1164, -33, -940, -1138, +189, -205, -362, -753,
- +18725, +12859, -7380, +4619, +4068, -1417, -1079, -1554, +4711, -1055, -8876, -550, +1948, -2355, -915, -3587, -1380, +839, -1610, +894, +413, -1080, -618, -661, -1073, +37, -840, -1169, +44, -15, -345, -1019,
- +20617, +14278, -9830, +2481, +4741, -181, -623, -1858, +4753, +25, -9421, -1889, +2095, -1425, -1076, -3758, -1263, +565, -1542, +933, +391, -1113, -672, -722, -1015, -8, -886, -996, +4, +105, -420, -1228,
- +22971, +14648, -11936, +1010, +4670, +1158, -431, -2361, +5156, +1040, -10169, -3060, +2153, -790, -797, -4032, -1000, +16, -1618, +1257, +163, -1228, -657, -703, -1282, -23, -913, -801, -89, +33, -392, -1315,
- +25010, +15029, -13660, +283, +4193, +2237, -295, -3037, +6357, +2181, -11344, -3815, +2283, -582, +157, -4078, -1205, -374, -1568, +1582, -149, -1216, -484, -731, -1677, +102, -841, -808, -116, +31, -256, -1422,
- +26769, +15204, -15115, +212, +3256, +2746, -305, -3981, +8274, +2753, -12585, -4021, +1747, -336, +1272, -4084, -1750, -584, -1463, +1491, -429, -1113, -280, -912, -2029, +54, -759, -856, -175, +86, -304, -1461,
- +28266, +15342, -16203, +581, +2138, +2848, -458, -4840, +10385, +2925, -13189, -4103, +831, +88, +2199, -3878, -2349, -502, -1510, +1038, -429, -929, -129, -1132, -2297, -63, -611, -925, -177, +40, -335, -1317,
- +29815, +15252, -16897, +1083, +956, +2943, -891, -5377, +12108, +2999, -12962, -4416, +24, +360, +3011, -3485, -2819, -229, -1736, +410, -242, -574, -195, -1310, -2449, -114, -453, -1000, -245, +121, -272, -1376,
- +30704, +15809, -17499, +1266, -67, +2973, -1441, -5841, +12884, +3441, -12109, -5095, -636, +265, +3716, -2998, -3240, +129, -2153, -287, -24, -180, -492, -1366, -2616, -99, -271, -1307, -188, +298, -393, -1578,
- +31618, +16165, -17687, +1138, -966, +3162, -2242, -6103, +13031, +3994, -10855, -5814, -1132, -114, +4440, -2576, -3472, +441, -2571, -925, +179, +66, -731, -1305, -2901, +118, -240, -1556, +32, +256, -573, -1665,
- +32352, +16428, -17457, +790, -1672, +3290, -2962, -6399, +12571, +4836, -9536, -6362, -1498, -662, +5052, -2203, -3513, +550, -2849, -1412, +253, +166, -883, -1139, -3109, +166, -209, -1529, +21, +58, -646, -1719,
- +32443, +17279, -16999, +233, -2175, +3032, -2969, -7266, +11609, +6215, -8405, -6559, -1896, -1197, +5401, -1763, -3376, +385, -2990, -1689, +180, +133, -974, -846, -3214, -83, +9, -1520, -177, -60, -770, -1566,
- +31892, +18478, -16118, -275, -2655, +2351, -2206, -8781, +10331, +8020, -7513, -6312, -2325, -1753, +5424, -1170, -3047, -34, -3062, -1782, +143, -158, -877, -571, -3280, -291, -54, -1441, -346, -233, -674, -1187,
- +30789, +19780, -14759, -548, -3198, +1460, -1025, -10799, +8894, +10055, -6732, -5809, -2497, -2429, +5133, -346, -2659, -573, -3168, -1582, +53, -566, -705, -356, -3272, -629, -135, -1412, -494, -112, -434, -955,
- +29203, +20906, -12769, -646, -3914, +632, +128, -12834, +7097, +11981, -5813, -5212, -2227, -3391, +4539, +673, -2372, -1121, -3072, -1520, +50, -953, -749, -83, -3467, -767, -412, -1439, -216, +10, -266, -671,
- +27369, +21887, -10304, -719, -4689, +134, +1044, -14260, +4701, +13487, -4266, -4865, -1191, -4653, +3796, +1775, -2279, -1199, -3034, -1527, +71, -1028, -1358, +221, -3301, -1300, -376, -1263, +67, +149, +70, -544,
- +25668, +22491, -8130, -702, -4924, -592, +1193, -14383, +1825, +13879, -1753, -4990, +70, -5585, +2485, +3061, -2364, -1028, -2910, -1941, +216, -1133, -2116, +371, -3234, -1474, -105, -1358, +438, +510, +66, -745,
- +24445, +22594, -6916, -408, -4078, -1908, +266, -13241, -891, +13193, +1079, -5162, +987, -5936, +931, +4120, -2150, -1025, -2529, -2729, -156, -699, -2958, -77, -2635, -1480, +97, -1388, +718, +673, -84, -802,
- +24036, +21606, -6204, +627, -3020, -3027, -1363, -11604, -2945, +12413, +3083, -5038, +1938, -6484, +131, +4636, -1658, -795, -2484, -3507, -351, -682, -3613, +80, -2402, -1272, +354, -1476, +898, +717, -205, -856,
- +23746, +20456, -5957, +1984, -1938, -4319, -2729, -9544, -5054, +11531, +5123, -5779, +3222, -6434, -1058, +5531, -1261, -866, -2359, -3656, -1163, -839, -3784, +272, -1846, -1591, +565, -1292, +952, +517, -310, -562,
- +23960, +19174, -6448, +3094, -1039, -5368, -3542, -7116, -6317, +9363, +7378, -6843, +3456, -4600, -3042, +6646, -852, -1642, -1443, -3885, -1943, -945, -3873, +318, -958, -2243, +620, -863, +528, +698, -367, -469,
- +23567, +18274, -6810, +4250, -385, -6084, -3975, -5591, -6825, +6911, +9455, -6771, +1918, -2142, -4373, +6456, +835, -2708, -1024, -3507, -2457, -992, -4100, +133, -369, -2407, +311, -628, +321, +831, -178, -597,
- +23143, +16836, -6902, +5727, -531, -6291, -3459, -5161, -7193, +5338, +10494, -6386, +648, -1274, -4124, +6012, +1743, -2864, -1093, -2840, -2832, -626, -4269, -880, -83, -2116, +209, -691, +146, +839, -37, -502,
- +22711, +15714, -7208, +6876, -1112, -6813, -1895, -4170, -8096, +3464, +11809, -6438, -833, +596, -4557, +5103, +2952, -2724, -1144, -2460, -2916, -73, -4033, -2509, -346, -1558, +340, -324, -568, +509, +520, -161,
- +21883, +15259, -8430, +8064, -235, -8167, -638, -2887, -8285, +800, +12561, -5050, -2930, +2356, -4439, +2991, +4720, -2205, -1490, -1642, -3457, +613, -3421, -4138, -736, -1237, +241, +437, -924, -343, +1118, +203,
- +21336, +14054, -8898, +8815, +778, -8299, -1119, -1073, -7651, -2227, +13016, -3460, -4273, +3243, -3776, +1237, +5044, -803, -1471, -1297, -3268, +457, -2964, -4426, -1137, -1555, +51, +1032, -730, -630, +878, +351,
- +20364, +12658, -8776, +9749, +928, -8029, -658, -913, -7055, -3196, +11978, -2563, -4312, +3779, -3422, -39, +4857, -93, -856, -1070, -2919, +46, -2987, -3874, -1261, -1841, -597, +1113, -366, -282, +474, -132,
- +19013, +11105, -7802, +10307, +543, -7199, -275, -1181, -6482, -3416, +10634, -2108, -4042, +4151, -2777, -1409, +4761, +291, -1107, -73, -2791, -368, -2750, -3871, -721, -1726, -1380, +656, -107, +32, +532, -418,
- +17238, +9876, -6359, +10305, +398, -6315, -102, -1089, -5867, -3730, +9349, -1363, -3939, +4046, -1704, -2280, +4126, +804, -1450, +148, -1982, -710, -2585, -3457, -636, -1203, -1796, +107, -115, +106, +736, -435,
- +16850, +7680, -7300, +12520, +2285, -8479, -1087, +427, -4800, -1828, +6635, -3369, -2358, +3423, -1655, -892, +2571, -327, -160, +642, -662, +1201, -1048, -1605, +229, -1235, -1428, -365, -1650, -1331, -434, -718,
- +14445, +7248, -5479, +10890, +2224, -6676, -847, +20, -3992, -1849, +5544, -2552, -2301, +2914, -1338, -1107, +2267, -66, -274, +451, -432, +1011, -1109, -1445, +210, -1200, -1152, -150, -1229, -1064, -619, -638,
- +12262, +7034, -3826, +9064, +2556, -4912, -1000, -85, -3259, -1912, +4712, -1765, -2260, +2378, -779, -1142, +1866, +240, -211, +297, -362, +843, -852, -1395, +26, -936, -987, +115, -841, -918, -540, -612,
- +10302, +6772, -2608, +7425, +3047, -3580, -1144, +38, -2705, -1968, +3948, -1167, -2245, +1845, -376, -1032, +1522, +265, -101, +261, -453, +682, -692, -1289, -83, -615, -752, -59, -567, -670, -472, -618,
- +8655, +6443, -1690, +6216, +3422, -2584, -975, +289, -2316, -1951, +3369, -755, -2184, +1494, -28, -828, +1147, +375, +103, +99, -381, +549, -584, -1004, +111, -444, -718, -65, -432, -490, -423, -480,
- +7221, +6029, -1043, +5350, +3704, -1861, -720, +491, -2015, -1932, +2857, -505, -2070, +1231, +249, -749, +916, +588, -26, +2, -231, +492, -373, -773, +146, -331, -639, -153, -420, -446, -268, -366,
- +6149, +5337, -522, +4890, +3705, -1298, -409, +653, -1896, -1811, +2394, -329, -1930, +1021, +457, -665, +862, +483, -128, +133, -8, +453, -352, -564, +224, -355, -685, -251, -418, -327, -123, -232,
- +5347, +4865, -12, +4345, +3331, -784, +8, +681, -1713, -1654, +1950, -310, -1698, +1128, +488, -580, +778, +296, +168, +368, -71, +403, -167, -481, +0, -380, -642, -237, -238, -203, -161, -399,
- +4513, +4458, +327, +3862, +3291, -212, +50, +538, -1286, -1648, +1413, -6, -1274, +809, +432, -246, +709, +464, +342, +239, -48, +380, -170, -546, -158, -340, -484, -110, -208, -423, -383, -436,
- +3737, +4010, +796, +3404, +3194, +416, -10, +338, -902, -1429, +1024, +156, -1024, +609, +727, +264, +595, +355, +422, +205, -29, +258, -264, -566, -23, -135, -442, -273, -489, -465, -296, -300,
- +3244, +3768, +1128, +2910, +3135, +692, -253, +385, -416, -1327, +523, +399, -524, +860, +1068, +205, +374, +460, +341, +111, -88, +108, -72, -266, -80, -420, -614, -364, -338, -321, -247, -281,
- +2573, +3501, +1542, +2422, +3009, +997, -86, +399, -529, -1166, +615, +927, +3, +728, +933, +166, +369, +430, +133, +29, +88, +270, -37, -461, -485, -479, -438, -286, -266, -299, -341, -359,
- +2231, +3444, +1513, +2040, +3101, +1062, -319, +337, -154, -486, +938, +903, +105, +773, +781, +97, +163, +295, +372, +236, +56, -55, -435, -564, -350, -311, -370, -314, -370, -380, -309, -324,
- +2099, +3103, +1628, +2260, +2332, +675, +355, +998, +218, -292, +974, +821, +239, +834, +457, -122, +408, +649, +268, -133, -357, -207, -248, -398, -297, -330, -451, -420, -307, -346, -285, -262,
- +2122, +2791, +1338, +2074, +2185, +1299, +1098, +1022, +96, -224, +1143, +1002, +34, +360, +626, +337, +351, +217, -313, -387, -92, +1, -292, -456, -393, -443, -464, -373, -291, -249, -256, -321,
- +1707, +2474, +1550, +2358, +2684, +1380, +926, +1182, +372, +34, +972, +722, +127, +725, +656, -121, -188, -80, -126, -77, -58, -130, -419, -521, -423, -415, -422, -288, -194, -281, -292, -289,
- +2009, +3271, +2261, +2063, +1937, +1369, +1101, +993, +457, +278, +709, +981, +479, -169, -163, -155, -17, +78, -53, -120, -289, -340, -416, -495, -424, -327, -303, -303, -181, -220, -289, -318,
- +2008, +3310, +2283, +1883, +1850, +1562, +1336, +1209, +776, +362, +614, +893, +94, -536, -228, +27, +139, +104, -127, -295, -281, -260, -428, -460, -357, -327, -324, -261, -177, -196, -244, -322,
- +1917, +2862, +1700, +1658, +1732, +1613, +1699, +1958, +1364, +660, +516, +154, +109, -111, -309, -59, +186, +33, -209, -177, -238, -291, -369, -419, -336, -324, -384, -275, -151, -205, -230, -271,
- +2083, +2983, +1506, +1369, +1260, +1246, +1868, +2065, +1340, +757, +550, +543, +648, -21, -250, -120, -176, +2, -56, -272, -389, -249, -240, -367, -275, -212, -264, -298, -255, -207, -278, -316,
- +2198, +2902, +1108, +1182, +1319, +951, +937, +1441, +1654, +1337, +1100, +824, +681, +876, +211, -700, -323, -124, -65, -79, -310, -308, -251, -253, -245, -200, -273, -191, -287, -316, -203, -334,
- +2056, +2797, +1106, +1111, +1388, +1207, +805, +382, +604, +1281, +1542, +1132, +810, +896, +1118, +443, -493, -486, -254, -141, -40, -152, -378, -280, -153, -282, -256, -141, -244, -319, -313, -273,
- +2227, +2815, +713, +806, +1269, +1147, +860, +283, +11, +688, +1122, +928, +1193, +1393, +1389, +1011, +515, +126, -365, -592, -318, -110, -213, -289, -293, -274, -243, -88, -185, -280, -240, -271,
- +2487, +3077, +731, +1027, +1384, +982, +654, -128, +18, +996, +561, +73, +591, +932, +1479, +1270, +870, +925, +448, -201, -501, -563, -415, -115, -143, -320, -310, -120, -171, -247, -175, -287,
- +2775, +3186, +631, +1392, +1798, +1197, +294, -934, -91, +1380, +530, -194, +56, +369, +981, +652, +864, +1272, +870, +557, +177, -277, -677, -549, -265, -205, -167, -195, -284, -238, -143, -268,
- +3354, +3952, +622, +1159, +1616, +1212, +384, -1193, -171, +1340, +276, -317, +73, +202, +505, +358, +412, +812, +941, +759, +457, +303, +14, -361, -589, -473, -252, -41, -106, -338, -312, -210,
- +3851, +4360, +508, +1396, +1995, +1083, -118, -1646, +204, +1680, -168, -602, -109, +183, +637, +36, +22, +528, +357, +402, +649, +527, +382, +246, -154, -411, -536, -224, -139, -252, -213, -373,
- +4411, +4791, +385, +1660, +2324, +1023, -690, -2047, +660, +1766, -479, -607, -315, +44, +662, -70, -18, +284, +30, +175, +102, +352, +562, +305, +304, +207, -224, -238, -340, -387, -265, -275,
- +5196, +5589, +252, +1519, +2294, +877, -1040, -2105, +1073, +1563, -889, -523, -328, -3, +615, -267, -54, +275, -150, -65, -69, +83, +148, +190, +385, +349, +230, +269, -184, -470, -345, -462,
- +5718, +5975, +175, +2056, +2782, +433, -1979, -2126, +1813, +1397, -1262, -508, -449, +38, +582, -483, -40, +268, -347, -79, -259, -144, +146, -223, +11, +368, +235, +504, +304, -118, -274, -506,
- +6315, +6714, +139, +2135, +3020, +109, -2674, -1982, +2425, +978, -1604, -368, -505, +111, +586, -693, -117, +249, -464, -85, -325, -245, +4, -438, -62, +108, +23, +446, +291, +123, +139, -256,
- +6745, +7502, +262, +2112, +3265, -191, -3399, -1845, +3011, +575, -2029, -233, -551, +131, +609, -828, -184, +190, -609, -176, -413, -318, +53, -619, -305, +55, -89, +207, +130, -29, +147, +100,
- +7135, +8455, +528, +1753, +3383, -342, -3912, -1715, +3302, +347, -2377, -280, -478, +73, +666, -864, -309, +173, -675, -305, -523, -417, -31, -619, -370, -108, -188, +168, -8, -183, -48, -243,
- +7313, +9335, +990, +1537, +3442, -503, -4294, -1670, +3510, +231, -2617, -467, -433, +51, +676, -780, -520, +145, -610, -381, -642, -599, -117, -669, -413, -163, -232, +54, +96, -400, -473, -157,
- +7366, +10104, +1617, +1432, +3413, -641, -4433, -1789, +3563, +295, -2857, -581, -471, -47, +733, -715, -694, +95, -548, -428, -666, -773, -215, -762, -547, -237, -183, +203, -336, -503, -328, -397,
- +7627, +10884, +2189, +1075, +3085, -556, -4178, -2011, +3118, +500, -2883, -799, -373, -262, +585, -455, -843, -134, -419, -461, -781, -795, -264, -872, -798, -151, -218, -232, -138, -459, -588, -350,
- +7805, +11222, +3062, +1025, +2511, +140, -3881, -2575, +2792, +742, -2671, -862, -572, -376, +526, -340, -707, -443, -595, -287, -600, -934, -448, -730, -617, -528, -615, +39, -258, -504, -448, -459,
- +8363, +10906, +3309, +2010, +2235, +305, -3931, -2743, +2509, +616, -2212, -1029, -818, -300, +441, -402, -584, -720, -757, -88, -693, -1025, -498, -478, -772, -805, -578, -256, -196, -436, -534, -482,
- +9029, +10207, +3227, +3604, +2126, +318, -3990, -2699, +2282, -66, -1506, -870, -1243, -147, +313, -594, -347, -843, -960, -75, -980, -749, -429, -936, -470, -770, -924, -178, -239, -505, -518, -435,
- +9921, +9094, +2287, +6032, +2825, -665, -3976, -1942, +1634, -1240, -452, -499, -1858, -63, +175, -661, -141, -1007, -1221, -134, -966, -783, -874, -746, -300, -913, -822, -399, -257, -376, -363, -634,
- +11207, +8923, +714, +7384, +3504, -1787, -3331, -478, +667, -3182, +480, +632, -2340, -174, -41, -734, +254, -1209, -1563, +237, -1495, -1119, -374, -1179, -176, -742, -854, -326, -296, -187, -407, -889,
- +12500, +9128, -1225, +8120, +4706, -2957, -3096, +1429, +224, -5655, +633, +2334, -2476, -521, -246, -1021, +659, -1250, -1598, -102, -1942, -946, -536, -1243, -56, -809, -795, -9, -245, -516, -388, -591,
- +13676, +9715, -3224, +8146, +6300, -3786, -3252, +3385, +497, -7984, -273, +4084, -1795, -1036, -439, -1428, +900, -738, -2169, -270, -1884, -1560, -244, -1157, -225, -702, -726, +327, -337, -781, -147, -433,
- +15154, +10710, -5567, +6975, +8141, -3612, -4028, +4575, +1224, -9451, -1863, +5048, -504, -1304, -849, -1887, +1317, -802, -2679, +65, -2243, -1967, -192, -1025, -170, -751, -680, +394, -331, -789, -111, -452,
- +16751, +11590, -7670, +5697, +9423, -3002, -4671, +5673, +1938, -10472, -3508, +5316, +1125, -1098, -1562, -2113, +1531, -1067, -2689, -22, -2225, -2260, -408, -719, -88, -730, -829, +416, -248, -657, -207, -430,
- +19048, +11932, -9850, +4534, +10090, -1984, -5054, +6461, +2293, -11027, -4690, +4999, +2637, -594, -2197, -2457, +1788, -1314, -2837, +89, -2336, -2296, -497, -623, +34, -680, -1066, +461, -55, -678, -251, -446,
- +21615, +12285, -12393, +3218, +10447, -513, -5263, +6448, +2499, -11072, -5490, +4213, +3638, +192, -2622, -3085, +2128, -1593, -3108, +258, -2535, -2078, -721, -584, +167, -802, -1230, +548, +77, -824, -300, -503,
- +23814, +13115, -14900, +2298, +10402, +898, -5101, +6133, +3297, -10978, -6160, +3330, +4213, +1402, -2845, -3633, +2406, -1782, -3197, +506, -2620, -1975, -705, -585, +213, -896, -1169, +725, -33, -930, -208, -501,
- +26386, +12827, -16969, +2278, +9703, +1341, -4735, +5967, +4345, -11169, -7039, +2751, +4328, +2440, -3053, -3808, +2333, -2300, -2829, +717, -2947, -2030, -466, -759, +120, -952, -975, +828, -420, -898, -159, -497,
- +27944, +13492, -18792, +2616, +8679, +1183, -4343, +5611, +6445, -11341, -8610, +2448, +4449, +2910, -2638, -3722, +1665, -2447, -2294, +737, -3191, -2075, -286, -1008, +16, -802, -857, +864, -755, -842, -70, -604,
- +29685, +13246, -19821, +3525, +7289, +438, -4363, +5714, +8745, -11618, -10243, +2318, +4494, +2830, -1737, -3623, +798, -2252, -1923, +676, -3494, -1846, -281, -1396, -10, -574, -760, +810, -964, -876, +89, -884,
- +30876, +13227, -20231, +4464, +5889, -395, -4997, +6035, +11190, -11731, -11571, +2002, +4359, +2564, -389, -3809, +115, -1644, -2030, +671, -3672, -1473, -429, -1750, -81, -276, -628, +609, -946, -950, +127, -1298,
- +31278, +13828, -20217, +5005, +4867, -1003, -6198, +6112, +13378, -11330, -12204, +1134, +4093, +2243, +984, -3911, -507, -785, -2404, +550, -3517, -1127, -734, -1985, -167, -11, -527, +311, -626, -1201, -142, -1426,
- +31763, +14606, -20213, +4922, +4300, -1334, -7821, +5934, +15019, -10488, -12296, -244, +3894, +2145, +1899, -3668, -996, -217, -2645, +278, -3186, -960, -1050, -2098, -246, +125, -509, +271, -479, -1663, -297, -1411,
- +32059, +15063, -19624, +4534, +3996, -1550, -9300, +5401, +15706, -8935, -11963, -1825, +3576, +2337, +2148, -3207, -1061, -200, -2557, +23, -2815, -964, -1297, -2112, -372, +106, -371, +213, -866, -1642, -555, -1453,
- +31594, +16148, -18709, +3873, +3953, -1965, -10020, +3854, +16002, -6585, -11621, -3362, +3109, +2803, +1915, -2572, -712, -591, -2348, +118, -2607, -1103, -1413, -2224, -397, +185, -559, -36, -1026, -1584, -771, -1168,
- +30561, +17638, -17451, +3091, +3826, -2310, -9959, +1289, +16030, -3803, -11272, -4403, +2328, +3336, +1431, -1843, -11, -1291, -1874, +345, -2491, -1351, -1564, -2198, -272, -81, -1106, +216, -1299, -1439, -527, -1224,
- +29054, +19377, -15810, +1898, +3337, -2040, -9228, -2236, +15567, -882, -10760, -4753, +1128, +3442, +1193, -1335, +949, -1929, -1501, +721, -2539, -1679, -1649, -1976, -762, -420, -1351, +363, -1271, -1184, -487, -1395,
- +27602, +19984, -13330, +1384, +2220, -1553, -8967, -5440, +14956, +1794, -10257, -4554, -131, +2570, +2016, -1408, +1844, -1852, -1851, +1473, -2793, -1890, -1630, -2378, -1270, -515, -1540, +663, -952, -1427, -261, -1350,
- +25630, +20290, -10249, +1324, +1107, -1114, -8918, -8485, +14115, +4665, -9857, -4277, -756, +606, +3451, -1301, +1865, -565, -2709, +1877, -2367, -2459, -1746, -2677, -1920, -340, -1413, +665, -508, -1675, -66, -1466,
- +23903, +20683, -7286, +510, -377, -53, -7840, -11202, +11907, +7374, -9146, -4087, -105, -1982, +4052, -56, +1078, +860, -2851, +1241, -1622, -2794, -2100, -2674, -2293, -321, -1039, +386, -96, -1780, -277, -1191,
- +22823, +20723, -6390, +1262, +38, -1708, -6903, -11540, +8654, +9407, -7731, -4726, +1287, -3835, +3356, +1929, +303, +1232, -2157, +96, -909, -2590, -2708, -1999, -2763, -486, -647, +74, -134, -1612, -437, -1074,
- +23286, +19705, -6984, +2708, +768, -3874, -6807, -9892, +5577, +9767, -5818, -5461, +2601, -4494, +2384, +2776, +168, +931, -1602, -159, -1262, -1698, -2885, -1466, -2698, -1301, -450, -206, -5, -1620, -620, -969,
- +23121, +19255, -7571, +3875, +1563, -5614, -6214, -8564, +2641, +9601, -3111, -6567, +3743, -4320, +945, +3692, -1043, +1590, -1282, -840, -479, -978, -2698, -1087, -2537, -2252, -520, -532, +376, -1513, -1259, -735,
- +23895, +17231, -7926, +5603, +1022, -6360, -5559, -7729, +248, +9659, -1110, -7381, +4032, -2981, -753, +3497, -675, +212, -226, -663, -11, -138, -2841, -1009, -2052, -2616, -1508, -419, +202, -1307, -1387, -864,
- +24342, +16471, -9991, +7124, +2357, -8386, -5329, -5315, -1440, +7468, +1850, -7622, +3025, -1191, -1868, +2925, -544, -837, +462, +724, -295, +355, -2494, -1379, -1397, -2680, -2066, -975, -223, -1077, -799, -950,
- +24670, +15431, -12280, +9290, +3619, -10800, -4710, -2736, -2869, +4919, +4375, -7414, +1744, +298, -2787, +2517, -329, -1185, +786, +1117, +234, +534, -2350, -1334, -1274, -2503, -2002, -1594, -1255, -755, -99, -851,
- +25053, +13472, -13783, +11903, +3737, -12350, -3755, -973, -3561, +2410, +5792, -6487, +903, +639, -3500, +2947, +120, -1823, +1427, +635, +328, +1654, -2795, -1081, -1079, -2818, -1321, -1807, -2368, -781, +236, -570,
- +25116, +10992, -14060, +14345, +2919, -12891, -2578, +298, -4831, +849, +7344, -6355, -113, +1687, -3785, +2243, +1525, -1852, +673, +891, +28, +1939, -1939, -1636, -642, -2710, -1531, -1027, -2946, -1438, +260, -246,
- +23985, +9052, -12782, +15373, +1674, -11878, -1468, -66, -5434, +491, +7676, -6469, -622, +2840, -3942, +1270, +2660, -1561, +29, +815, -200, +1925, -1493, -1644, -301, -2510, -1767, -674, -2584, -1874, -316, -165,
- +21931, +7984, -10773, +14942, +1323, -10330, -1496, -41, -5153, -560, +7563, -5510, -1367, +3202, -3067, +472, +2598, -1083, +280, +328, -550, +2171, -1750, -1359, +265, -2505, -1617, -565, -2257, -1696, -689, -545,
- +19430, +7714, -9051, +13883, +1898, -9550, -1479, +550, -5119, -1546, +7412, -4342, -2191, +3447, -2123, -382, +2504, -635, +149, +475, -754, +1639, -1244, -1582, +373, -1789, -1679, -351, -2065, -1520, -554, -754,
- +15748, +5880, -5425, +14058, +1054, -9150, +6, +395, -3696, +26, +2379, -3599, +1707, +2155, -2493, -381, +1177, -628, -908, +221, -185, +13, -490, +744, +822, +168, +287, -448, -1045, -444, -892, -1472,
- +13423, +5793, -3949, +12100, +1504, -7414, -200, +63, -3202, +36, +2192, -2942, +1203, +1913, -1964, -650, +802, -427, -791, -12, -102, +329, -386, +362, +832, +203, -6, -415, -837, -549, -728, -965,
- +11547, +5785, -2873, +10302, +2118, -6063, -463, +55, -2706, -44, +2080, -2250, +641, +1766, -1389, -907, +655, -241, -693, -30, +34, +406, -343, +364, +574, +40, +171, -246, -795, -541, -534, -664,
- +9992, +5645, -2205, +8952, +2516, -5038, -463, +97, -2247, -98, +1995, -1860, +247, +1695, -1144, -964, +569, -79, -605, +22, +220, +235, -242, +317, +304, +54, +320, -69, -720, -432, -411, -602,
- +8782, +5267, -1688, +7925, +2586, -4032, -444, +186, -1797, -191, +1866, -1605, +27, +1498, -942, -933, +555, +32, -524, +199, +141, +118, -129, +149, +324, +142, +325, +78, -560, -385, -344, -545,
- +7729, +4882, -1177, +6873, +2650, -3039, -407, +340, -1509, -165, +1693, -1465, -61, +1352, -781, -864, +627, +111, -305, +152, +24, +234, -129, +182, +391, +215, +338, +94, -398, -277, -266, -463,
- +6682, +4405, -731, +6123, +2845, -2298, -387, +459, -1188, -176, +1393, -1251, -73, +1145, -660, -560, +620, +101, -161, +95, +165, +308, -117, +224, +453, +233, +340, +124, -276, -83, -284, -652,
- +5690, +4114, -370, +5337, +2959, -1597, -302, +540, -969, -272, +1211, -1020, -123, +962, -388, -419, +496, +293, -68, +198, +277, +243, -1, +258, +446, +244, +316, +224, -197, -287, -538, -753,
- +4886, +3783, -77, +4739, +3009, -1004, -171, +567, -808, -296, +1071, -732, -150, +762, -143, -243, +583, +495, +70, +295, +285, +282, +109, +300, +419, +303, +318, -41, -410, -429, -543, -696,
- +4226, +3500, +214, +4230, +2888, -619, +78, +571, -807, -209, +1096, -674, -362, +872, +202, -45, +765, +519, +142, +420, +299, +326, +177, +298, +271, +19, +43, -216, -432, -470, -647, -770,
- +3932, +3487, +332, +3583, +2646, -337, +285, +627, -784, -249, +992, -484, -225, +1185, +515, -8, +833, +683, +354, +372, +256, +357, +26, -114, -52, -13, -48, -275, -631, -669, -560, -678,
- +3417, +3033, +572, +3583, +2497, -132, +512, +448, -821, -41, +1094, -215, +63, +1208, +613, +421, +1026, +661, +269, +268, +157, -77, -316, -230, -50, -15, -270, -450, -631, -506, -489, -682,
- +3181, +2995, +715, +3281, +2345, -67, +347, +573, -324, +109, +1136, +26, +360, +1541, +983, +492, +841, +521, -21, -138, -249, -144, -314, -277, -62, -239, -335, -379, -509, -456, -497, -624,
- +2727, +2772, +1072, +2985, +1995, +392, +618, +698, +14, +104, +1230, +616, +773, +1489, +881, +385, +451, -79, -396, -153, -251, -293, -476, -335, -58, -202, -314, -426, -485, -422, -544, -580,
- +2494, +2557, +1043, +2809, +2364, +870, +612, +794, +496, +543, +1308, +960, +905, +1098, +463, -159, -22, -97, -245, -365, -543, -373, -259, -109, -161, -351, -340, -303, -434, -540, -495, -424,
- +2244, +2930, +1654, +2496, +2296, +1063, +990, +1335, +682, +721, +1328, +513, +346, +642, +45, -321, -153, -280, -469, -425, -401, -290, -203, -148, -250, -401, -344, -391, -436, -433, -426, -380,
- +2037, +3030, +1906, +2584, +3062, +1893, +990, +1134, +771, +385, +555, +134, +140, +441, -13, -448, -353, -397, -487, -345, -327, -238, -229, -306, -339, -347, -307, -358, -440, -470, -365, -304,
- +2260, +3620, +2531, +2997, +2841, +1693, +1371, +1050, +54, -313, +437, +310, -186, +172, -15, -693, -347, -145, -477, -380, -271, -292, -232, -289, -368, -327, -359, -335, -337, -420, -362, -300,
- +2676, +4646, +3139, +2421, +2169, +1461, +1102, +750, +196, +85, +103, -264, -85, +79, -270, -444, -278, -319, -366, -267, -356, -287, -310, -325, -320, -352, -353, -348, -336, -368, -283, -304,
- +2949, +4690, +2841, +1992, +1689, +1410, +1437, +860, +277, +660, +273, -352, -345, -179, +121, -193, -595, -313, -69, -302, -301, -297, -388, -283, -359, -329, -293, -304, -317, -316, -248, -264,
- +2663, +4197, +2446, +1659, +1599, +1195, +1150, +1390, +834, +702, +922, +74, -262, -12, -178, -353, -146, -141, -372, -189, -146, -406, -452, -309, -320, -299, -251, -248, -234, -286, -278, -279,
- +2398, +3447, +2003, +1730, +1358, +984, +1031, +668, +683, +1466, +1326, +833, +547, +62, +124, -145, -512, -263, -44, -260, -496, -309, -241, -380, -321, -210, -197, -195, -288, -327, -348, -283,
- +1987, +2518, +1256, +1700, +1770, +1374, +486, -161, +666, +1239, +1117, +1441, +1412, +1138, +952, +102, -154, -108, -471, -390, -130, -296, -423, -224, -149, -219, -273, -144, -187, -306, -316, -312,
- +2277, +2839, +857, +1089, +1531, +1252, +447, -170, +485, +946, +625, +786, +1274, +1596, +1572, +803, +425, +213, -154, -308, -514, -316, -104, -287, -376, -112, -81, -229, -298, -346, -243, -269,
- +2475, +3091, +1057, +1202, +1523, +1181, +155, -419, +779, +1083, +35, +243, +607, +800, +1330, +1039, +902, +962, +366, -99, -203, -378, -433, -305, -177, -196, -314, -134, -130, -427, -342, -186,
- +2867, +3436, +954, +1406, +1896, +1116, -228, -668, +1005, +1052, -200, +160, +322, +441, +627, +249, +723, +1109, +691, +570, +250, -239, -146, -317, -437, -152, -136, -255, -367, -288, -235, -306,
- +3223, +4037, +1059, +1327, +1971, +1123, -496, -724, +1262, +822, -504, +196, +267, +346, +542, -168, +79, +604, +516, +608, +511, +379, +188, -138, -157, -106, -291, -239, -240, -438, -390, -237,
- +3604, +4513, +1093, +1460, +2232, +986, -1011, -692, +1601, +582, -689, +154, +137, +264, +549, -231, -112, +308, -5, +126, +288, +386, +454, +334, +190, +65, -9, -169, -440, -448, -309, -360,
- +4214, +5204, +1001, +1333, +2363, +811, -1317, -468, +1657, +218, -774, +195, +54, +193, +477, -310, -143, +220, -205, -91, -167, -47, +273, +245, +485, +588, +199, -41, -178, -454, -469, -319,
- +4699, +5772, +1037, +1391, +2580, +571, -1811, -137, +1930, -248, -876, +278, -102, +158, +529, -367, -232, +173, -250, -176, -332, -250, -145, -125, +369, +578, +501, +334, -24, -230, -185, -365,
- +5288, +6343, +926, +1516, +2837, +116, -2274, +403, +2022, -767, -921, +321, -140, +29, +469, -385, -290, +151, -299, -257, -451, -381, -272, -339, +52, +314, +302, +289, +305, +49, -70, -194,
- +5726, +6820, +1096, +1667, +3026, -179, -2850, +907, +2339, -1355, -1017, +450, -163, -66, +415, -378, -412, +166, -245, -345, -541, -415, -353, -452, -62, +81, +100, +97, +117, +54, +153, +24,
- +6153, +7423, +1241, +1705, +3192, -342, -3363, +1287, +2593, -1875, -1019, +557, -240, -122, +319, -290, -434, +2, -201, -386, -582, -375, -458, -561, -160, +6, +81, -90, -141, -171, +10, +136,
- +6828, +8181, +890, +1848, +3361, -805, -3382, +1527, +2488, -2165, -973, +617, -316, -246, +308, -188, -549, -125, -176, -412, -641, -381, -560, -633, -100, -94, -15, -180, -313, -244, -131, -157,
- +7339, +8745, +841, +2086, +3460, -1152, -3508, +1614, +2597, -2420, -1103, +713, -354, -350, +308, -133, -681, -241, -127, -375, -784, -526, -527, -641, -141, -117, -177, -223, -325, -365, -249, -300,
- +7574, +9152, +1067, +2490, +3582, -1504, -3603, +1572, +2713, -2475, -1389, +742, -241, -424, +146, -29, -689, -412, -49, -482, -922, -508, -528, -656, -326, -236, +0, -242, -494, -465, -250, -363,
- +7771, +9477, +1527, +2680, +3445, -1316, -3581, +1119, +2776, -2355, -1714, +883, -172, -648, +99, -15, -445, -536, -388, -395, -960, -596, -496, -760, -479, -221, +19, -221, -514, -524, -422, -579,
- +8021, +9527, +2130, +2911, +3042, -704, -3474, +429, +2652, -2057, -1809, +694, -37, -769, -100, +184, -247, -761, -609, -325, -1000, -680, -746, -736, -332, -408, -31, -128, -468, -729, -608, -586,
- +8404, +9096, +2503, +3785, +2807, -578, -3480, +263, +2211, -1959, -1522, +174, -65, -508, -392, +128, +9, -898, -776, -193, -1245, -945, -832, -687, -337, -524, -93, -26, -595, -926, -547, -887,
- +8807, +8295, +2417, +5558, +3298, -1393, -3611, +1274, +1418, -2498, -541, -286, -448, +137, -733, -107, +472, -919, -800, -132, -1516, -1020, -876, -819, -258, -573, -75, -222, -470, -870, -816, -827,
- +9721, +7750, +1320, +7320, +3992, -2723, -3178, +2422, -20, -3129, +726, -465, -1243, +477, -680, -418, +820, -960, -919, -87, -1553, -1159, -1230, -839, -90, -743, -335, -154, -533, -893, -664, -1012,
- +10870, +7707, -280, +8285, +5199, -3799, -2870, +3710, -1420, -4018, +2054, -220, -2214, +514, -188, -855, +1016, -762, -1123, +24, -1500, -1380, -1443, -763, -169, -955, -493, -100, -557, -806, -616, -1159,
- +11833, +8327, -2134, +8341, +6953, -4401, -2931, +5077, -2393, -5396, +3185, +626, -3054, -50, +496, -988, +898, -338, -1369, +122, -1461, -1366, -1542, -1049, -218, -1029, -640, -181, -361, -866, -501, -1048,
- +12829, +9031, -3811, +7670, +8588, -4509, -3175, +6408, -3118, -7036, +3841, +1817, -3527, -1043, +839, -699, +618, +2, -1465, -51, -1246, -1421, -1712, -1253, -467, -1107, -577, -354, -342, -807, -350, -891,
- +14193, +9389, -5197, +6872, +9549, -4273, -3139, +7727, -3898, -8441, +3999, +3031, -3444, -2122, +727, -197, +556, +113, -1327, -318, -1040, -1564, -1813, -1380, -747, -1085, -601, -339, -469, -645, -199, -888,
- +15661, +9657, -6466, +6233, +9751, -3871, -2723, +8959, -4623, -9557, +3687, +4006, -2825, -3063, +218, +188, +872, +40, -1085, -476, -1213, -1459, -1966, -1538, -758, -1196, -697, -106, -518, -710, -84, -846,
- +17612, +9338, -7642, +6082, +9245, -3958, -1634, +10145, -5734, -10179, +3233, +4461, -2053, -3596, -499, +236, +1471, -53, -824, -783, -1511, -1205, -2322, -1376, -936, -1374, -531, +50, -558, -860, -125, -756,
- +19463, +9219, -8893, +6261, +8413, -4281, -363, +11374, -6530, -10787, +2801, +4644, -1342, -3682, -1194, -39, +2157, +139, -767, -1072, -1682, -1101, -2364, -1296, -1186, -1329, -395, +235, -591, -1146, -127, -554,
- +21650, +9391, -10922, +6081, +8229, -4220, +202, +11812, -6628, -11097, +2478, +4559, -1182, -3433, -1549, -554, +2784, +461, -1205, -1027, -1704, -1258, -2251, -1431, -1146, -1205, -447, +400, -669, -1391, -60, -370,
- +23618, +9863, -13021, +6004, +8047, -4224, +416, +12157, -6101, -11654, +2261, +4560, -1406, -3057, -1488, -1343, +3208, +953, -1820, -705, -1697, -1485, -2065, -1531, -1035, -1118, -452, +413, -760, -1496, +104, -350,
- +25507, +10091, -14633, +6037, +7728, -4437, +358, +12536, -5172, -12313, +2012, +4630, -1785, -2622, -1212, -2223, +3337, +1463, -2227, -360, -1728, -1658, -1788, -1625, -1024, -963, -484, +363, -873, -1530, +387, -597,
- +26627, +10861, -15853, +5976, +7293, -4687, -371, +13070, -3740, -13126, +1550, +4641, -1970, -2334, -931, -3002, +3015, +1972, -2297, -262, -1622, -1706, -1631, -1718, -1043, -847, -523, +200, -913, -1491, +419, -863,
- +27529, +11441, -16338, +5805, +6853, -5062, -1537, +13789, -2342, -13609, +1025, +4352, -1778, -2113, -836, -3461, +2445, +2244, -1905, -447, -1343, -1486, -1806, -1634, -1063, -761, -595, -38, -809, -1509, +121, -852,
- +28224, +11700, -16026, +5571, +6480, -5603, -2945, +14554, -1154, -13550, +445, +3703, -1208, -1832, -1081, -3648, +1918, +2132, -1094, -755, -1071, -949, -2221, -1385, -1073, -728, -775, -144, -846, -1640, -17, -888,
- +28214, +12317, -15132, +5336, +6093, -6385, -4398, +15063, +169, -13141, -349, +2865, -289, -1493, -1675, -3631, +1627, +1567, -67, -871, -1083, -137, -2567, -1204, -1005, -901, -818, -487, -1098, -1321, -264, -1047,
- +27674, +13198, -13952, +5049, +5725, -7019, -5818, +14656, +1734, -12326, -1241, +1915, +642, -1155, -2395, -3373, +1425, +664, +785, -409, -1488, +642, -2474, -1372, -798, -1009, -1376, -899, -968, -1199, -318, -1143,
- +26652, +14012, -12267, +5200, +5059, -7687, -7096, +13622, +3659, -11441, -2232, +1136, +1363, -745, -2920, -3117, +1275, -215, +1173, +578, -1926, +1018, -1813, -1727, -552, -1508, -1936, -882, -1218, -880, -117, -1274,
- +25476, +14976, -10645, +5041, +4465, -7268, -8563, +11373, +5951, -10470, -2967, +695, +1268, -121, -2916, -3040, +1232, -1049, +1136, +1691, -1847, +783, -939, -1782, -1189, -1393, -2259, -1210, -1263, -527, +246, -1345,
- +24418, +15887, -9483, +5106, +3650, -6572, -9308, +8066, +7947, -9122, -3698, +546, +799, +234, -2298, -3040, +979, -1401, +660, +2460, -1414, +581, -594, -1924, -1571, -1185, -2342, -1526, -1293, -276, +512, -1388,
- +23795, +16122, -8471, +5677, +2738, -6335, -9272, +4879, +8930, -7283, -4533, +587, +584, -12, -1140, -3045, +596, -1168, -297, +2828, -664, +171, -697, -1636, -1755, -862, -2122, -1839, -1085, -590, +469, -1065,
- +23181, +16390, -7741, +6442, +2203, -6740, -8434, +1898, +8933, -4752, -5617, +579, +1155, -849, +75, -2508, -62, -548, -1446, +2589, +243, -427, -620, -1078, -1599, -627, -1538, -1798, -1522, -1117, +586, -608,
- +22030, +16813, -6552, +6365, +1905, -6491, -7923, -1054, +8742, -2377, -6611, +561, +1892, -1729, +1053, -1623, -1078, +90, -2143, +1121, +1073, -290, -801, -281, -1302, -213, -1096, -1925, -1798, -1686, +156, -224,
- +21251, +16564, -5227, +6101, +1298, -5618, -7958, -3289, +8275, -752, -6864, +468, +2279, -1970, +1851, -1720, -1502, +720, -2997, -87, +1066, +346, -609, +374, -840, -207, -612, -1924, -1832, -2459, -669, -2,
- +21059, +15707, -4300, +6487, +399, -4731, -7511, -5182, +7533, +993, -7053, +282, +3472, -2462, +1927, -1518, -1924, +1110, -3285, -499, +296, +615, +989, +279, -802, +498, -387, -1895, -1824, -2715, -1623, -344,
- +21308, +14470, -4242, +7387, -252, -4583, -6956, -6093, +6238, +2376, -6555, -258, +4580, -2860, +1045, -858, -2358, +1013, -2617, -1140, +487, +118, +1239, +1477, -1144, +905, +15, -2196, -1670, -2549, -2403, -914,
- +21749, +13551, -6010, +9423, +237, -6449, -5831, -5696, +4659, +3069, -5379, -988, +5203, -3101, -229, +148, -2474, +413, -1565, -777, +245, -263, +270, +2911, -521, +46, +1169, -2577, -2021, -1583, -2762, -1790,
- +22949, +11670, -8631, +12918, +409, -9740, -4092, -3756, +2385, +3036, -3324, -2593, +5421, -2472, -2044, +991, -1723, -438, -884, +258, -444, -546, -80, +2348, +873, +112, +640, -1839, -2303, -1429, -2266, -2374,
- +23912, +9195, -9740, +15651, -753, -10898, -2348, -2548, +736, +2645, -1865, -3420, +5193, -2092, -2914, +1332, -608, -827, -805, +690, -265, -735, -758, +2026, +1239, +685, +402, -1265, -2108, -2026, -1548, -2057,
- +24116, +7253, -10354, +17453, -1244, -12053, -838, -452, -1755, +1608, +585, -4398, +4021, -759, -3062, +841, +208, -518, -792, +316, -185, -122, -1534, +1707, +1529, +201, +1161, -889, -2381, -1596, -1536, -1868,
- +22899, +6009, -9723, +18156, -1387, -12297, +387, +197, -3319, +1403, +1627, -5089, +3452, +505, -3305, +713, +563, -709, -310, -26, -425, +286, -1418, +1157, +1256, +363, +1114, -493, -2226, -1184, -1308, -2261,
- +20564, +5546, -8226, +17550, -828, -11490, +294, +435, -3523, +690, +1926, -4747, +2908, +1152, -2973, +467, +625, -707, -390, +101, -449, +40, -906, +959, +763, +546, +863, -551, -1476, -956, -1217, -2071,
- +18013, +5812, -6919, +15896, +403, -10591, +67, +717, -3782, +91, +2336, -4162, +2130, +1919, -2779, -103, +1086, -691, -833, +297, -250, -202, -650, +1014, +731, +166, +703, -484, -1293, -477, -1156, -1837,
- +15954, +7279, -4696, +11257, -415, -7760, +15, -732, -924, +300, -779, -1111, +2316, +31, -1667, -359, +362, -476, -1406, +77, +201, +160, +31, +184, +33, +618, +402, -142, -19, -131, -351, -177,
- +13494, +6705, -2870, +10505, -334, -6612, +28, -1001, -670, +405, -783, -1035, +2308, +178, -1639, -390, +219, -411, -1192, +78, +48, +72, +135, +215, +200, +619, +296, -179, +63, -49, -474, -174,
- +11237, +6344, -1097, +9098, -68, -4982, -506, -1321, -184, +563, -966, -831, +2204, +226, -1398, -487, +210, -400, -1067, +109, +7, -13, +137, +290, +364, +506, +81, -34, +85, -87, -211, -95,
- +9435, +6226, -171, +7621, +609, -3889, -842, -1290, +79, +593, -877, -638, +1778, +372, -1115, -612, +133, -304, -919, +84, +28, -9, +49, +403, +518, +117, +63, +315, +9, -189, +148, +127,
- +8281, +6134, -52, +6557, +1253, -3449, -792, -804, +3, +410, -398, -491, +1170, +585, -801, -816, +97, -92, -760, -8, +125, +10, +14, +591, +350, +20, +334, +355, -11, +73, +387, +50,
- +7625, +5926, -212, +5732, +1440, -2973, -409, -538, -153, +402, +53, -528, +814, +714, -773, -751, +187, -25, -685, +71, +194, -126, +301, +656, +141, +177, +495, +460, +123, +277, +255, -206,
- +6929, +5539, -213, +5156, +1489, -2470, -128, -421, -216, +512, +263, -626, +604, +666, -598, -609, +135, +2, -569, +170, +101, +124, +603, +290, +211, +558, +624, +396, +73, +189, -68, -300,
- +6185, +4980, +12, +4844, +1476, -2007, +5, -218, -48, +475, +186, -579, +652, +583, -532, -454, +163, -44, -351, +323, +185, +454, +519, +323, +554, +596, +513, +149, -59, +27, -156, -301,
- +5578, +4710, +139, +4160, +1511, -1429, +247, -167, -134, +535, +301, -478, +484, +512, -357, -355, +143, +139, +9, +323, +460, +774, +454, +456, +460, +265, +311, +29, -141, -56, -157, -425,
- +4834, +4247, +381, +3890, +1667, -1077, +239, -52, +64, +515, +186, -374, +470, +446, -204, -178, +260, +402, +264, +582, +786, +717, +277, +144, +133, +174, +219, +36, -212, -220, -241, -491,
- +4111, +3866, +739, +3569, +1573, -633, +462, -99, +98, +570, +132, -353, +509, +570, +1, -45, +535, +857, +514, +702, +653, +127, -67, +94, +33, +142, +132, -176, -297, -218, -361, -612,
- +3730, +3751, +749, +2995, +1740, -73, +398, -128, +157, +562, +322, -106, +526, +653, +398, +535, +911, +896, +331, +268, +196, +17, -50, +13, -44, +14, +4, -239, -323, -300, -491, -605,
- +2892, +3209, +1362, +3059, +1608, +182, +476, -76, +432, +661, +242, +160, +1034, +1084, +626, +638, +748, +381, -9, +164, +81, +56, -148, -220, -132, -95, -61, -252, -388, -412, -527, -492,
- +2752, +3422, +1354, +2301, +1710, +560, +500, +0, +522, +1109, +816, +680, +1165, +1033, +440, -19, +152, +356, +205, +72, -219, -249, -230, -203, -210, -180, -256, -370, -297, -417, -460, -470,
- +2213, +3015, +1710, +2495, +1858, +590, +641, +619, +1215, +1482, +1045, +756, +541, +266, +10, +87, +388, +325, -149, -273, -65, -313, -465, -315, -243, -222, -297, -239, -314, -374, -410, -472,
- +2378, +3632, +1949, +1796, +1538, +1419, +1931, +1407, +1042, +906, +324, -55, +57, +281, +416, +73, -141, +104, -125, -338, -346, -567, -456, -178, -236, -293, -193, -168, -347, -459, -409, -412,
- +2533, +3615, +2312, +2871, +2388, +1873, +1924, +743, -6, +118, +67, +58, +149, +131, +262, -115, -211, -1, -357, -465, -469, -597, -378, -114, -162, -284, -237, -201, -345, -426, -423, -455,
- +2942, +4615, +3780, +3595, +1951, +1001, +577, -3, -9, +178, +100, -150, -79, +35, +232, -191, -343, -241, -527, -515, -469, -366, -285, -260, -253, -164, -168, -307, -405, -445, -401, -430,
- +3532, +6354, +4764, +2112, +192, +502, +1060, +740, -280, -481, -6, +64, -3, -232, +35, -123, -425, -424, -500, -331, -403, -411, -380, -233, -195, -219, -156, -328, -390, -471, -421, -332,
- +3754, +6378, +3302, +1176, +770, +1524, +1808, +405, -520, -9, +89, -401, +38, -134, -211, -179, -439, -279, -348, -439, -354, -411, -499, -252, -186, -273, -220, -306, -347, -364, -422, -391,
- +2291, +3472, +1957, +1996, +2277, +2297, +2104, +987, +507, +706, +356, -152, -298, -91, -5, -385, -390, -196, -226, -195, -416, -447, -287, -389, -410, -244, -292, -350, -178, -230, -400, -417,
- +1819, +2518, +1138, +1323, +2016, +2067, +1584, +1227, +1540, +1527, +1077, +599, +319, +222, -133, -344, -224, -354, -392, -98, -287, -313, -172, -348, -336, -273, -365, -452, -322, -244, -281, -244,
- +1991, +2736, +1265, +1355, +1696, +1270, +711, +599, +1244, +1618, +1273, +1004, +935, +768, +344, -110, -219, -251, -264, -319, -400, -274, -131, -258, -317, -231, -396, -403, -299, -400, -335, -208,
- +2251, +2968, +994, +1270, +1801, +1182, +278, +85, +960, +1169, +719, +996, +1351, +1194, +875, +354, +176, -35, -282, -178, -385, -406, -153, -263, -175, -84, -340, -346, -297, -435, -353, -295,
- +2479, +3474, +1165, +1200, +1738, +845, +57, +328, +1004, +611, +199, +546, +759, +1002, +1149, +732, +519, +336, +110, +42, -306, -317, -221, -391, -190, -72, -254, -255, -285, -409, -356, -289,
- +2648, +3711, +1310, +1382, +2036, +687, -508, +326, +1209, +455, +69, +381, +353, +462, +570, +467, +723, +755, +406, +258, +135, -71, -226, -267, -244, -225, -239, -248, -226, -295, -370, -333,
- +2964, +4131, +1490, +1331, +2035, +615, -807, +460, +1251, +53, -30, +484, +328, +176, +292, +67, +31, +459, +630, +520, +346, +231, +64, -123, -179, -163, -253, -368, -325, -244, -286, -364,
- +3240, +4589, +1670, +1277, +2158, +577, -1140, +581, +1323, -227, -122, +553, +290, +100, +235, -70, -152, +21, +69, +287, +434, +552, +333, +96, +114, -5, -177, -258, -330, -382, -258, -309,
- +3730, +5196, +1638, +1123, +2168, +499, -1274, +755, +1209, -628, -139, +668, +292, -40, +122, -92, -234, -100, -101, -83, -135, +285, +479, +374, +279, +151, +85, -119, -293, -348, -282, -381,
- +4119, +5684, +1732, +1126, +2228, +300, -1467, +1077, +1204, -1061, -263, +742, +305, -24, +37, -204, -274, -137, -131, -189, -340, -114, +44, +178, +404, +348, +234, +110, -83, -267, -257, -291,
- +4622, +6186, +1693, +1242, +2320, -46, -1538, +1517, +1127, -1483, -304, +841, +294, -67, +5, -203, -308, -200, -102, -217, -386, -222, -141, -99, +23, +201, +346, +265, +65, -52, -11, -200,
- +5193, +6638, +1553, +1499, +2388, -594, -1569, +2013, +985, -1862, -401, +847, +342, -127, -49, -265, -391, -279, -24, -258, -446, -237, -373, -107, -35, -174, -57, +100, +163, +130, +55, -58,
- +5824, +7125, +1374, +1701, +2443, -1077, -1576, +2426, +806, -2127, -438, +769, +324, -176, +41, -326, -603, -328, -5, -213, -487, -284, -470, -142, -47, -263, -242, -262, -124, +12, +120, +33,
- +6335, +7628, +1408, +1800, +2526, -1396, -1736, +2894, +798, -2493, -400, +738, +274, -165, +15, -222, -694, -482, +72, -261, -572, -116, -475, -277, -17, -291, -261, -317, -412, -297, -56, +28,
- +6761, +8075, +1459, +2066, +2609, -1964, -1828, +3359, +727, -2782, -456, +715, +208, -232, -18, -148, -747, -627, +81, -302, -698, -121, -406, -325, -107, -219, -294, -466, -521, -391, -176, -288,
- +7157, +8606, +1581, +2068, +2784, -2202, -2039, +3602, +767, -2899, -542, +707, +104, -260, -9, -128, -676, -844, +64, -130, -840, -253, -381, -284, -107, -233, -282, -564, -568, -421, -261, -447,
- +7410, +9322, +1838, +1630, +3033, -1959, -2478, +3478, +916, -2764, -738, +578, +126, -372, +30, -107, -667, -935, -60, -32, -777, -452, -481, -148, -144, -362, -257, -530, -598, -498, -436, -437,
- +7600, +9757, +2318, +1422, +3068, -1530, -2951, +3205, +1134, -2618, -848, +362, +153, -421, -49, -52, -609, -1028, -173, +13, -822, -437, -527, -269, -108, -428, -361, -411, -698, -654, -354, -475,
- +8104, +9762, +2543, +1907, +2993, -1492, -3123, +3108, +1007, -2376, -799, +85, +225, -462, -207, +76, -422, -1156, -330, +104, -791, -492, -526, -345, -141, -393, -383, -537, -744, -705, -190, -505,
- +8909, +9413, +2318, +2985, +3009, -1948, -3050, +3168, +425, -2046, -543, -270, +167, -483, -337, +79, -154, -1299, -550, +186, -643, -695, -585, -287, -262, -358, -406, -740, -843, -531, -265, -573,
- +9426, +9025, +2181, +4009, +3640, -2472, -3407, +3777, -384, -2061, +272, -562, -296, -282, -348, -201, +397, -1463, -821, +375, -577, -753, -723, -199, -322, -387, -483, -747, -845, -590, -326, -571,
- +10108, +8385, +1400, +6014, +4224, -3846, -2895, +4634, -1924, -2185, +1409, -691, -736, -445, -160, -496, +690, -1211, -1255, +419, -429, -745, -766, -201, -456, -411, -561, -544, -937, -907, -160, -739,
- +10943, +8373, +46, +7110, +5244, -4697, -2467, +5334, -3432, -2574, +2681, -670, -1220, -664, +155, -796, +596, -633, -1639, +276, -169, -751, -786, -162, -512, -556, -561, -560, -872, -1006, -393, -823,
- +12145, +8720, -1664, +7093, +6723, -4974, -2355, +5841, -4655, -3092, +3716, -397, -1752, -903, +493, -914, +75, -59, -1625, -196, +169, -746, -800, +30, -700, -607, -584, -846, -650, -980, -876, -718,
- +13449, +9173, -3433, +6797, +7856, -4807, -2042, +6051, -5634, -3740, +4384, +233, -2242, -1265, +790, -884, -471, +114, -1201, -709, +233, -517, -817, +265, -855, -714, -702, -983, -688, -985, -936, -805,
- +14554, +9843, -4692, +5589, +8876, -3969, -1993, +6452, -6471, -4465, +4658, +1064, -2464, -1808, +1040, -734, -892, -140, -587, -969, -47, -87, -824, +496, -902, -929, -759, -1132, -899, -928, -701, -988,
- +15499, +10690, -5588, +4019, +9370, -2825, -1817, +6925, -7237, -5143, +4618, +1819, -2391, -2377, +1112, -527, -1082, -687, -144, -864, -451, +270, -610, +501, -919, -981, -876, -1386, -1039, -897, -490, -928,
- +17184, +10743, -6654, +3458, +8941, -2496, -296, +6958, -8428, -5131, +4435, +2201, -2279, -2678, +1041, -465, -1059, -1191, -112, -563, -633, +396, -146, +255, -999, -772, -1178, -1541, -1165, -955, -285, -586,
- +18439, +11433, -7884, +3086, +8223, -2330, +1154, +7363, -9381, -5433, +4476, +2299, -2058, -2772, +772, -429, -922, -1487, -412, -319, -459, +489, +179, +4, -920, -666, -1378, -1593, -1381, -989, -70, -199,
- +20043, +11571, -8926, +2927, +7480, -2933, +2814, +7900, -10432, -5634, +4629, +2163, -2083, -2501, +322, -605, -660, -1666, -795, -420, +2, +773, +28, -86, -714, -788, -1426, -1661, -1631, -934, -18, +154,
- +21100, +12438, -9991, +2658, +6924, -3598, +3640, +9112, -11048, -6263, +4923, +1936, -2083, -2127, -90, -1004, -241, -1755, -1109, -655, +353, +1477, -496, -26, -322, -1103, -1235, -1773, -1804, -950, -17, +340,
- +22220, +13016, -10684, +2238, +6616, -4544, +3961, +10464, -11476, -6710, +4989, +1692, -2097, -1740, -471, -1509, +171, -1891, -1172, -1008, +446, +2361, -1007, -80, +206, -1448, -1059, -1719, -2148, -946, -187, +379,
- +23160, +13514, -10970, +1648, +6564, -5582, +3717, +11856, -11585, -6851, +4668, +1415, -1888, -1527, -831, -1885, +423, -2020, -993, -1361, +246, +3145, -1090, -388, +815, -1543, -1101, -1488, -2586, -1060, -470, +329,
- +23984, +13865, -11140, +1506, +6153, -6455, +3221, +12728, -11274, -6683, +4149, +879, -1350, -1515, -1321, -1966, +480, -2107, -735, -1620, -134, +3538, -695, -707, +1213, -1214, -1434, -1269, -3012, -1293, -736, +72,
- +24782, +14120, -11236, +1961, +5253, -7111, +2788, +12880, -10420, -6360, +3471, +290, -601, -1551, -1881, -1800, +635, -2271, -409, -1692, -623, +3484, +102, -645, +1121, -484, -1860, -1402, -3095, -1550, -1113, -154,
- +24478, +15178, -10478, +1270, +5126, -7637, +1416, +13108, -9038, -6194, +2475, -43, +4, -1635, -2240, -1773, +998, -2517, -301, -1320, -1403, +2910, +1377, -319, +543, +368, -2377, -1572, -2886, -2071, -1188, -610,
- +23336, +16618, -8704, -223, +5298, -7565, -968, +13263, -6982, -6465, +1742, -449, +352, -1376, -2596, -1623, +1240, -2651, -286, -899, -1898, +1936, +2438, +528, -375, +750, -2161, -1941, -2664, -2274, -1304, -958,
- +22712, +17229, -7217, -356, +4386, -7099, -2807, +12389, -4621, -6839, +1425, -975, +424, -777, -2826, -1526, +1422, -2734, -246, -516, -2068, +1271, +2387, +1470, -861, +696, -1581, -2206, -2447, -2243, -1214, -1282,
- +22892, +17053, -6909, +1550, +2504, -7309, -2981, +10387, -2761, -6478, +847, -1462, +747, -527, -2541, -1653, +1330, -2326, -581, +131, -2018, +687, +1356, +2090, -263, +54, -772, -2199, -2423, -1678, -1280, -1950,
- +22958, +16963, -6994, +3862, +804, -8094, -2421, +7964, -1267, -5599, -222, -1546, +1312, -701, -1892, -1941, +925, -1306, -1223, +805, -1822, -507, +577, +2232, +644, +10, -622, -1590, -2129, -1759, -1313, -2053,
- +22795, +16811, -6665, +5414, -231, -8963, -2057, +5715, -140, -4502, -1495, -1224, +1967, -1203, -1238, -1944, +128, +141, -1762, +375, -1151, -1442, -293, +2236, +1381, +482, -421, -1050, -2081, -1865, -1013, -2075,
- +22156, +16822, -5737, +5914, -531, -9248, -2574, +3914, +921, -3656, -2319, -843, +2476, -1480, -1050, -1438, -455, +614, -1691, -640, -770, -1051, -1218, +1623, +1962, +1863, -702, -1229, -1009, -2137, -1191, -1810,
- +21420, +16785, -4799, +6154, -663, -9035, -3372, +2102, +2124, -2833, -3110, -133, +2641, -1601, -638, -1248, -923, +605, -1675, -1249, -658, -53, -1902, +1335, +2038, +2064, +272, -1486, -537, -2097, -1156, -1644,
- +21361, +15629, -3750, +6528, -1323, -8215, -4323, +464, +3132, -1840, -3943, +437, +3186, -1861, -582, -1384, -980, +77, -1818, -753, -1149, +490, -779, +520, +1069, +2103, +1599, -1602, -997, -1118, -1205, -1803,
- +20330, +15116, -2198, +6125, -1778, -6323, -6028, -1388, +5002, -1330, -4769, +1469, +3125, -2056, -350, -2178, -854, +367, -2722, -22, -540, -99, +456, +351, -11, +1824, +1553, -531, -893, -1195, -631, -1855,
- +20062, +13940, -1073, +5901, -2918, -4148, -6485, -3763, +6395, -76, -5571, +1976, +3170, -2469, -500, -2482, -418, +183, -3077, +751, +150, -824, +890, +1089, -685, +923, +962, +419, -69, -1542, -261, -1391,
- +21165, +12566, -2644, +7196, -3419, -4374, -5591, -3941, +6004, +491, -4989, +1625, +3132, -2899, -840, -2060, -308, +352, -2926, +725, +461, -401, +854, +946, -597, +286, +687, +245, +522, -714, -834, -655,
- +22181, +10753, -4743, +9694, -3820, -6164, -3751, -3237, +4762, +962, -4786, +856, +3566, -3082, -1668, -1292, +74, +282, -2679, +317, +654, +206, +432, +672, -272, -199, +427, +115, +322, +278, -897, -731,
- +21833, +9209, -6007, +12315, -3453, -8356, -2210, -1380, +3074, +222, -3684, +199, +3572, -2831, -2010, -495, +19, -33, -2094, +470, +147, +334, +628, +538, -358, +45, -17, -272, +825, +112, -396, -410,
- +21222, +7854, -6428, +13904, -3314, -9841, -311, -717, +1107, +600, -2989, -732, +3598, -2074, -2105, -29, +34, -558, -1422, +552, -367, +238, +799, +488, -473, +119, +72, -314, +618, +130, -262, -1,
- +19959, +7458, -6254, +13163, -2749, -8575, +168, -1541, +524, +795, -2410, -1167, +3370, -1359, -1981, +131, -37, -600, -1272, +322, -134, +241, +366, +572, -360, -40, +508, -76, -11, +77, -84, -39,
- +18263, +7315, -5697, +12058, -1512, -7911, -155, -1097, -277, +440, -1476, -1163, +2794, -682, -1653, -226, +195, -447, -1525, +167, +243, +191, +5, +420, -166, +267, +536, -17, -141, -216, +13, -120,
- +14574, +8295, -838, +5767, -2715, -2520, -1691, -1773, +1779, -38, -2463, +993, +2121, -1350, -803, -1187, +196, -325, -1656, +367, -300, -397, +308, +424, +622, +1154, -257, -779, -260, -661, -212, +363,
- +12640, +8177, -514, +5232, -1427, -2829, -1332, -1356, +968, +94, -1951, +761, +1867, -950, -840, -1080, +224, -469, -1525, +376, -426, -453, +483, +403, +530, +830, -326, -345, -235, -760, -56, +349,
- +11044, +7881, -148, +5139, -839, -2943, -771, -1231, +563, +131, -1472, +726, +1552, -637, -706, -854, +77, -516, -1176, +229, -479, -289, +444, +438, +558, +439, -291, +63, -149, -710, +13, +439,
- +9448, +7315, +777, +4791, -766, -2291, -640, -1240, +566, +79, -1184, +670, +1401, -496, -584, -601, -102, -472, -972, +95, -341, -227, +329, +485, +481, +177, -40, +272, -35, -470, -18, +555,
- +7784, +6813, +1919, +4053, -580, -1299, -807, -1308, +740, +180, -1143, +616, +1306, -404, -321, -523, -263, -345, -754, -11, -288, -134, +224, +482, +339, +206, +285, +426, +140, -377, +51, +463,
- +6153, +6246, +2936, +3514, -265, -522, -963, -1330, +954, +278, -1137, +468, +1183, -27, -199, -727, -188, -39, -737, -145, -161, -167, +296, +467, +191, +475, +664, +574, +50, -370, +118, +236,
- +5216, +5838, +3133, +3059, +1, -157, -756, -1165, +778, +326, -848, +372, +928, +178, -109, -801, -20, +104, -796, -199, -47, -58, +362, +449, +343, +811, +845, +385, -220, -311, +33, +113,
- +4597, +5368, +3150, +2849, +47, +176, -392, -1164, +650, +523, -570, +155, +748, +467, -67, -777, +130, +87, -748, -20, -18, +143, +685, +510, +516, +926, +646, +76, -295, -314, +101, +201,
- +4160, +4800, +2975, +2878, +215, +185, -346, -879, +720, +434, -577, +142, +805, +500, -153, -718, +261, +104, -689, +154, +246, +528, +763, +288, +509, +781, +225, -155, -161, -171, -27, -42,
- +4047, +4610, +2554, +2523, +343, +309, -161, -677, +639, +395, -412, +331, +729, +219, -6, -351, +190, +142, -205, +534, +514, +540, +360, +158, +449, +446, +134, -82, -194, -248, -36, -79,
- +3681, +4202, +2459, +2522, +468, +335, -124, -483, +720, +451, -371, +292, +718, +292, +137, -143, +474, +547, +124, +441, +403, +249, +3, +182, +383, +387, +48, -193, -191, -244, -51, -202,
- +3418, +3958, +2332, +2406, +561, +275, -16, -147, +764, +316, -330, +555, +677, +300, +712, +391, +554, +506, -31, +195, +200, -92, +90, +358, +160, +198, -1, -186, -221, -248, -146, -268,
- +3294, +3885, +2237, +2055, +440, +495, +330, -195, +594, +558, -92, +562, +1070, +915, +915, +255, +158, +177, -224, +85, +144, -90, +60, +179, +169, +71, -152, -244, -264, -222, -259, -374,
- +3036, +3530, +2299, +2284, +540, +283, +250, +363, +785, +420, +481, +1288, +1245, +678, +546, -172, -123, +52, -133, +151, -76, -120, +87, +168, +37, -127, -184, -303, -217, -273, -383, -412,
- +2951, +3684, +2445, +1884, +210, +635, +675, +547, +1250, +1227, +765, +965, +798, +86, +80, -228, +0, +39, -228, +30, -27, -42, +25, +53, -221, -186, -201, -304, -216, -403, -409, -382,
- +2948, +3672, +2453, +1863, +191, +765, +1578, +1710, +1229, +774, +415, +256, +396, -103, +36, -65, -268, -80, -64, -3, -34, -116, -164, -71, -281, -296, -229, -301, -271, -378, -434, -341,
- +2843, +3566, +2452, +2150, +1119, +1466, +1682, +1795, +928, -254, -261, +372, +403, -274, -165, -161, -184, -111, -88, -48, -200, -201, -180, -289, -413, -275, -295, -256, -268, -441, -348, -288,
- +2564, +4101, +3460, +2647, +1410, +1412, +1574, +983, +11, +28, -27, +71, +225, -244, +4, -163, -265, +10, -151, -168, -99, -187, -352, -372, -357, -210, -195, -232, -258, -356, -289, -290,
- +3244, +5969, +3950, +1503, +762, +1387, +767, +390, +603, -90, -364, -54, +452, -41, -367, -79, -184, -274, -111, -48, -196, -322, -399, -360, -258, -194, -183, -224, -289, -330, -316, -345,
- +3784, +6054, +3526, +1790, +389, +352, +1278, +1092, -88, -197, +260, -59, +139, +65, -157, -256, -333, -279, -121, -80, -211, -244, -442, -312, -216, -247, -254, -250, -268, -326, -359, -335,
- +2822, +5085, +3846, +2069, +435, +648, +1401, +1023, +236, -6, +341, +350, +172, -40, +34, -202, -361, -272, -304, -204, -29, -187, -395, -181, -217, -302, -314, -303, -311, -325, -288, -335,
- +2707, +4855, +2989, +1364, +947, +1039, +1087, +968, +768, +256, +227, +682, +564, +111, +39, -39, -213, -415, -274, -193, -240, -136, -135, -139, -171, -174, -321, -402, -386, -337, -287, -323,
- +2574, +4549, +2481, +1104, +1330, +907, +475, +1038, +988, +424, +619, +680, +540, +614, +433, -71, -59, -64, -397, -356, -134, -141, -286, +11, +52, -193, -195, -312, -434, -438, -356, -279,
- +2422, +4172, +2328, +1283, +1472, +647, +125, +1006, +879, +224, +547, +905, +832, +557, +435, +418, +214, -78, -116, -201, -318, -253, -140, -84, -96, +29, -87, -310, -305, -394, -495, -381,
- +2457, +4168, +2312, +1258, +1473, +568, -47, +1024, +903, -67, +189, +852, +771, +615, +723, +347, +177, +387, +190, -226, -97, -8, -307, -173, +62, -42, -182, -125, -211, -363, -347, -400,
- +2479, +4135, +2339, +1562, +1610, +192, -248, +1300, +909, -337, +81, +690, +508, +388, +636, +433, +219, +291, +303, +164, +7, +21, +31, -36, -110, -67, -84, -238, -296, -215, -282, -331,
- +2624, +4417, +2420, +1461, +1611, +190, -334, +1254, +921, -411, -37, +569, +431, +277, +366, +238, +20, +196, +411, +163, +23, +266, +197, +88, +161, +35, -197, -291, -298, -316, -320, -247,
- +2857, +4661, +2448, +1599, +1644, -52, -369, +1426, +846, -542, -64, +578, +333, +106, +438, +207, -300, -149, +268, +191, +20, +247, +302, +342, +299, +211, +96, -235, -456, -375, -272, -328,
- +3188, +5067, +2423, +1526, +1665, -114, -379, +1420, +746, -615, -22, +514, +244, +36, +349, +284, -291, -398, -114, +35, -95, +71, +386, +395, +370, +407, +245, -45, -298, -398, -392, -348,
- +3392, +5464, +2575, +1426, +1705, -141, -510, +1546, +697, -819, -14, +541, +205, -81, +197, +362, -172, -517, -262, -166, -340, -129, +171, +384, +434, +397, +374, +107, -152, -237, -310, -366,
- +3778, +5985, +2547, +1224, +1789, -132, -599, +1611, +647, -931, +4, +483, +130, -67, +79, +336, -105, -481, -339, -274, -374, -355, -90, +280, +364, +297, +401, +185, -84, -89, -184, -264,
- +4238, +6510, +2468, +1077, +1860, -270, -600, +1756, +466, -1066, +75, +520, -27, -200, +61, +302, -74, -470, -390, -308, -412, -437, -214, +90, +251, +154, +227, +157, -56, -78, -125, -116,
- +4791, +7085, +2292, +969, +1933, -473, -530, +1936, +231, -1156, +164, +537, -117, -309, +2, +238, -84, -390, -352, -407, -462, -398, -204, -73, +172, +87, +45, +57, -238, -129, -20, -64,
- +5298, +7657, +2183, +875, +2016, -753, -494, +2218, -13, -1312, +267, +578, -182, -441, -93, +196, -122, -393, -302, -435, -513, -440, -113, -135, -14, +190, -70, -156, -337, -293, -128, -66,
- +5772, +8287, +2120, +701, +2131, -1043, -540, +2502, -218, -1459, +344, +564, -207, -513, -279, +141, -129, -411, -314, -481, -509, -495, -83, -55, -189, +147, -1, -322, -411, -420, -358, -159,
- +6156, +8940, +2162, +466, +2269, -1223, -655, +2753, -350, -1564, +441, +587, -308, -513, -366, -30, -129, -409, -289, -486, -560, -558, -73, +140, -206, -105, +70, -261, -507, -464, -575, -293,
- +6742, +9493, +2028, +426, +2287, -1512, -626, +2857, -609, -1493, +499, +542, -410, -555, -338, -271, -242, -367, -235, -522, -637, -614, -88, +199, -77, -219, -130, -145, -572, -543, -605, -493,
- +7455, +9892, +1817, +673, +2165, -1782, -526, +2877, -874, -1369, +613, +482, -471, -664, -187, -495, -430, -293, -210, -463, -712, -671, -39, +162, -43, -26, -317, -285, -509, -579, -619, -592,
- +8019, +10193, +1826, +947, +2060, -1895, -616, +2838, -973, -1270, +603, +513, -417, -884, -78, -555, -646, -328, -167, -385, -659, -776, -74, +250, -111, +117, -295, -476, -508, -590, -658, -581,
- +8488, +10358, +1977, +1265, +2015, -1887, -920, +2788, -1005, -1210, +617, +441, -268, -1020, -166, -487, -785, -574, -79, -286, -605, -796, -270, +464, -155, +23, -164, -502, -600, -692, -661, -560,
- +9032, +10338, +2002, +1761, +2191, -2067, -1283, +2872, -1174, -1205, +746, +309, -249, -938, -329, -531, -744, -897, -123, -86, -627, -738, -388, +469, +0, -188, -125, -361, -727, -819, -607, -613,
- +9864, +10088, +1523, +2776, +2578, -2733, -1373, +3075, -1563, -1189, +922, +251, -375, -786, -321, -773, -647, -1025, -380, +85, -536, -746, -274, +305, +98, -159, -216, -318, -746, -852, -593, -682,
- +10598, +9701, +940, +4274, +3058, -3831, -1125, +3536, -2290, -1265, +1285, +276, -567, -754, -134, -923, -659, -1033, -713, +96, -164, -899, -154, +299, +14, +105, -391, -378, -574, -830, -773, -577,
- +10878, +9347, +643, +5807, +3528, -5043, -576, +4279, -3492, -1535, +1951, +350, -873, -858, +153, -941, -755, -1006, -1030, -132, +274, -915, -234, +450, -136, +336, -408, -493, -454, -795, -947, -437,
- +11510, +9866, -517, +5809, +4860, -5267, -967, +4693, -4147, -1854, +2440, +298, -1178, -888, +429, -1109, -918, -824, -1173, -606, +385, -531, -456, +537, -109, +345, -322, -566, -435, -822, -1034, -491,
- +12635, +10354, -1762, +5073, +6221, -4898, -1391, +4717, -4535, -2049, +2756, +364, -1594, -867, +721, -1229, -1148, -678, -1099, -989, +154, -84, -438, +418, +119, +303, -273, -468, -478, -915, -1048, -631,
- +13739, +10931, -3039, +4229, +7036, -3993, -1627, +4425, -4683, -2247, +2950, +515, -2020, -897, +930, -1302, -1368, -646, -958, -1207, -291, +233, -188, +154, +374, +357, -256, -270, -569, -1081, -1002, -747,
- +14744, +11698, -4040, +3065, +7514, -2833, -1645, +3985, -4805, -2328, +2928, +769, -2368, -998, +1104, -1337, -1464, -742, -746, -1258, -738, +270, +219, -28, +461, +565, -183, -98, -674, -1208, -1015, -822,
- +15661, +12563, -4797, +1712, +7684, -1798, -1303, +3560, -5128, -2181, +2756, +928, -2517, -1206, +1167, -1348, -1484, -913, -576, -1200, -996, -13, +556, +59, +345, +829, -12, -35, -778, -1229, -1099, -956,
- +16364, +13610, -5417, +358, +7606, -1081, -694, +3363, -5713, -1853, +2574, +824, -2410, -1460, +1029, -1325, -1426, -1134, -452, -1081, -1063, -425, +647, +304, +234, +1059, +210, -50, -832, -1188, -1210, -1113,
- +17301, +14490, -6249, -381, +7171, -884, +239, +3371, -6504, -1381, +2548, +400, -2128, -1591, +701, -1356, -1209, -1399, -313, -902, -1081, -684, +503, +524, +231, +1359, +398, -161, -776, -1179, -1300, -1239,
- +19090, +14422, -7537, +119, +6088, -1186, +1568, +3110, -7218, -739, +2538, -295, -1756, -1656, +234, -1424, -1032, -1537, -233, -694, -1129, -779, +292, +571, +268, +1771, +559, -457, -623, -1262, -1420, -1267,
- +20805, +14336, -8736, +920, +4704, -1494, +2649, +2925, -7561, -328, +2504, -973, -1224, -1901, -205, -1369, -1023, -1413, -248, -538, -1010, -940, +175, +531, +207, +2290, +770, -842, -494, -1328, -1610, -1150,
- +22109, +14485, -9555, +1595, +3405, -1875, +3399, +2878, -7467, -159, +2320, -1375, -756, -2191, -602, -1235, -972, -1286, -262, -418, -788, -1088, +82, +594, -8, +2708, +1095, -1168, -535, -1285, -1751, -974,
- +22911, +14859, -9889, +1889, +2263, -2415, +3753, +2933, -7127, -227, +1986, -1630, -415, -2450, -1051, -1037, -827, -1434, -165, -366, -647, -1068, -154, +882, -368, +2616, +1524, -1241, -905, -1145, -1703, -979,
- +23245, +15363, -9604, +1856, +1322, -3040, +3776, +3098, -6633, -350, +1568, -1819, -103, -2618, -1435, -794, -655, -1757, +41, -318, -654, -746, -459, +1267, -738, +1911, +2006, -928, -1339, -994, -1484, -1026,
- +23048, +16128, -8809, +1596, +486, -3594, +3405, +3364, -5994, -577, +1227, -2110, +338, -2650, -1697, -633, -515, -2058, +200, -158, -867, -14, -786, +1297, -792, +869, +2115, -163, -1403, -1180, -994, -927,
- +22809, +16473, -7468, +1279, -304, -4094, +2691, +3769, -5530, -656, +858, -2440, +917, -2540, -1937, -596, -384, -2335, +377, -58, -950, +797, -1345, +1069, -434, -289, +1797, +898, -1234, -1327, -340, -1167,
- +22287, +16759, -6019, +907, -957, -4847, +1807, +4137, -5333, -671, +434, -2757, +1592, -2484, -2177, -772, -331, -2403, +180, +397, -1148, +952, -1488, +457, +9, -900, +941, +1571, -432, -1370, -331, -1254,
- +21687, +17120, -4653, +1201, -1531, -5605, +1233, +4224, -4907, -618, +334, -2824, +2339, -2255, -2444, -777, -345, -2119, +138, +690, -1476, +1035, -1282, -255, +720, -854, -197, +2118, +560, -1484, -235, -840,
- +20812, +17571, -3517, +1604, -1925, -6559, +655, +3983, -4426, -559, +260, -2689, +2858, -2122, -2599, -1007, -244, -1381, -668, +771, -1403, +492, -756, -404, +502, +93, -695, +1167, +1322, -839, -247, -943,
- +20139, +17539, -2371, +1932, -2101, -7422, -134, +3611, -3812, -412, +185, -2382, +3168, -1970, -3046, -567, -229, -1405, -1029, +419, -1307, +375, -467, -375, +380, +1214, -1001, -411, +2033, -274, -430, -799,
- +19753, +17050, -1457, +2572, -2382, -8049, -965, +2983, -2716, -235, -326, -1321, +2916, -2171, -2296, -826, -571, -1104, -1712, +62, -637, +159, -684, +668, +232, +865, +69, -1322, +1025, +254, +67, -588,
- +19313, +16611, -863, +3251, -2596, -8557, -2035, +2815, -1745, -84, -572, -839, +2943, -1918, -2229, -1014, -802, -1378, -1915, +318, -814, +322, -33, +499, +177, +995, +794, -1733, -313, +324, +698, -311,
- +19432, +15373, -280, +4094, -3296, -8664, -2599, +2170, -225, -30, -1542, +594, +2691, -2281, -1544, -1686, -1307, -903, -1915, -153, -126, +698, -360, +340, +825, +1064, +273, -993, -998, -689, +1129, +142,
- +19161, +14270, +164, +4902, -4023, -8420, -3080, +1712, +839, +173, -2097, +1066, +2771, -2396, -1584, -2406, -841, -783, -2457, +724, +24, +6, +115, +460, +603, +1331, -24, -638, -844, -1849, +898, +543,
- +18185, +13294, +1396, +5056, -4975, -6537, -4217, +256, +3477, -142, -3597, +2330, +2565, -2744, -1485, -2544, -786, -568, -2073, +767, -278, -87, +712, +47, +286, +1855, +49, -975, -401, -2019, -110, +720,
- +18313, +12559, +1145, +3915, -4788, -4611, -4800, -248, +4385, -385, -3737, +2444, +2059, -2542, -1236, -3085, -90, -60, -2227, +677, -342, +170, +590, -167, +444, +1928, +89, -943, -588, -1828, -345, +588,
- +19047, +11703, -955, +4365, -4893, -3853, -3267, -1533, +4299, +134, -4009, +2112, +2030, -2635, -1305, -2227, -55, -224, -2038, +767, -148, -368, +345, +393, +586, +1413, +142, -763, -846, -1547, -218, +199,
- +19014, +10464, -2335, +5732, -4481, -4151, -2526, -849, +3281, -472, -3208, +1847, +1902, -2824, -779, -1622, -183, -396, -1924, +1079, -378, -665, +394, +566, +672, +1279, -35, -701, -812, -1354, +31, +44,
- +18162, +9492, -3044, +7090, -3964, -4906, -1033, -851, +1796, -66, -2783, +1424, +1900, -2369, -665, -1270, -198, -516, -1532, +747, -522, -404, +331, +314, +897, +1359, -338, -718, -601, -1136, +5, +342,
- +16598, +8667, -2195, +6902, -3696, -3649, -980, -1771, +1921, -11, -2768, +1203, +2093, -1882, -722, -1121, -151, -296, -1570, +398, -363, -287, +171, +326, +918, +1214, -295, -849, -425, -762, -169, +362,
- +14574, +8452, +258, +4430, -4365, -2407, +102, -220, -223, -832, -1852, +1615, +1202, -2022, +253, -1216, -444, -63, -1455, +368, -312, -727, +373, +217, -412, +849, +339, -186, +129, -916, -296, -195,
- +12278, +8141, +1428, +3486, -3243, -1249, -493, -560, +165, -592, -1924, +1327, +1447, -1595, +92, -1011, -282, -108, -1214, +238, -313, -593, +289, +150, -236, +853, +317, -36, -85, -842, +19, -3,
- +9818, +8134, +2487, +2440, -2082, -590, -823, -829, +309, -432, -1752, +1141, +1209, -1118, +27, -830, -297, -203, -900, +148, -415, -552, +316, +48, -77, +666, +249, +139, -158, -658, +206, +196,
- +8218, +7700, +2637, +2474, -1307, -764, -546, -580, +192, -485, -1350, +993, +1042, -888, +8, -569, -372, -127, -680, -31, -355, -306, +131, -53, +119, +550, +383, +249, -130, -272, +357, +9,
- +7260, +6952, +2528, +2729, -947, -957, -177, -207, -119, -455, -915, +762, +893, -798, +106, -330, -495, -95, -429, -94, -346, -203, -44, +24, +289, +567, +633, +250, -96, -40, +210, -228,
- +6314, +6251, +2666, +2794, -629, -891, -34, +102, -183, -316, -716, +491, +887, -525, +110, -285, -414, +113, -262, -316, -185, -38, -118, +319, +459, +666, +731, +112, -104, -55, +52, -322,
- +5417, +5613, +2827, +2816, -327, -838, +28, +455, -189, -286, -591, +343, +896, -378, +146, -174, -275, +223, -276, -286, +110, +144, +58, +429, +461, +747, +496, -173, -50, +14, -42, -390,
- +4737, +5252, +2774, +2553, +28, -656, +97, +596, -174, -128, -477, +136, +904, -37, +86, -133, -68, +253, -71, +76, +414, +107, +44, +523, +339, +397, +292, -77, +23, -24, -184, -339,
- +3981, +4689, +2974, +2705, +128, -673, +191, +862, -76, -188, -396, +170, +926, +95, +102, -7, +257, +567, +232, +227, +237, +46, +2, +205, +229, +329, +244, -63, +38, -31, -270, -262,
- +3639, +4461, +2924, +2330, +166, -438, +386, +823, -29, -56, -316, +227, +932, +175, +339, +566, +570, +436, +183, +186, -95, -222, +17, +187, +153, +207, +145, +26, +72, -187, -282, -293,
- +3259, +4171, +2982, +2255, +67, -366, +661, +923, -74, +111, -202, +162, +1330, +741, +513, +485, +402, +353, -62, -283, -157, +6, -120, +24, +146, +186, +148, -35, -33, -267, -322, -309,
- +3122, +4118, +2900, +1944, +0, -98, +882, +1021, -181, +159, +515, +745, +1264, +473, +425, +351, -23, -30, -118, -265, -166, -97, -186, +192, +98, -114, +91, +11, -210, -322, -297, -412,
- +3235, +4303, +2623, +1571, +77, +285, +881, +1185, +547, +613, +652, +402, +925, +370, -45, -8, +19, -59, -264, -364, +11, +81, -230, -1, -128, -117, +119, -34, -321, -411, -265, -385,
- +3389, +4725, +2245, +1203, +58, +908, +2020, +1399, +334, +357, +538, +113, +387, +96, +39, -34, -209, -107, -173, -4, +62, -200, -339, -98, -124, -103, +123, -133, -427, -315, -196, -296,
- +3432, +4882, +1947, +1109, +1266, +1747, +1687, +1007, +236, +86, +163, -84, +293, +0, -42, -68, -271, +122, +155, -210, -251, -156, -291, -288, -163, +38, -58, -180, -248, -250, -248, -317,
- +3101, +4702, +2964, +1975, +929, +1541, +1764, +744, -57, -59, +188, -44, +87, -46, -2, +54, +100, +125, -120, -181, -166, -232, -402, -239, -149, -71, +43, -36, -164, -289, -356, -319,
- +3896, +5904, +2447, +896, +1159, +1573, +1310, +595, -175, -62, +179, +2, +162, -166, +142, +495, +86, -291, -23, -10, -305, -361, -351, -199, -209, +43, +163, +6, -270, -382, -312, -377,
- +4111, +6381, +2053, +273, +1154, +1396, +1209, +828, +5, -261, +331, +111, +75, +99, +333, +466, -15, -97, -25, -78, -294, -279, -352, -332, -105, +81, +175, -17, -195, -388, -359, -345,
- +3095, +5772, +3360, +570, +281, +922, +1379, +1273, +83, -225, +436, +376, -8, +55, +499, +520, +210, -84, -45, +41, -164, -351, -289, -251, -244, +17, +144, +52, -153, -277, -319, -362,
- +2581, +5083, +3747, +1205, +166, +554, +1050, +1250, +302, -212, +397, +598, +127, +67, +436, +383, +436, +172, +39, +53, -182, -180, -149, -287, -291, -5, +118, -12, -207, -177, -214, -333,
- +2552, +4951, +3531, +1372, +349, +359, +972, +1271, +183, -443, +321, +679, +210, +58, +442, +429, +340, +218, +211, +180, -63, -124, -120, -161, -112, -103, +24, +72, -222, -300, -275, -209,
- +2665, +4956, +3357, +1460, +482, +248, +879, +1296, +212, -508, +150, +505, +100, +12, +412, +341, +306, +406, +139, +62, +128, -3, -44, -39, -12, -31, +66, +41, -175, -338, -364, -294,
- +2910, +5172, +3202, +1418, +526, +219, +908, +1323, +135, -544, +153, +494, +74, -268, +195, +282, +179, +422, +266, +64, +20, -95, +137, +155, -18, +190, +178, +50, -99, -282, -367, -378,
- +3106, +5510, +3157, +1272, +654, +172, +826, +1393, +101, -594, +108, +460, +164, -335, -22, +133, -125, +219, +461, +52, -105, -110, +31, +176, +54, +285, +298, +145, +61, -223, -389, -316,
- +3368, +5932, +3118, +1145, +758, +78, +765, +1468, +37, -717, +138, +457, +120, -290, -144, +62, -257, -129, +404, +63, -206, -153, -100, +152, +60, +155, +386, +264, +71, -31, -197, -377,
- +3733, +6456, +3058, +942, +889, +25, +681, +1552, -15, -820, +148, +459, +69, -211, -190, -47, -265, -323, +274, +169, -372, -347, -72, +87, +21, +34, +374, +281, +11, +98, -68, -219,
- +4188, +7066, +2967, +691, +995, -34, +635, +1651, -188, -887, +235, +437, -43, -227, -100, -139, -354, -381, +96, +266, -304, -584, -157, +39, -36, +7, +204, +218, +59, +6, -48, -108,
- +4746, +7725, +2804, +457, +1072, -163, +664, +1759, -458, -963, +395, +430, -203, -287, -43, -200, -465, -426, -10, +200, -148, -659, -283, +63, -164, -51, +108, +49, +5, -21, -57, -176,
- +5293, +8424, +2691, +200, +1075, -352, +722, +1883, -811, -1091, +593, +430, -407, -391, +9, -266, -633, -524, -73, +107, -103, -596, -428, +55, -134, -199, +69, -190, -167, +13, -143, -226,
- +5863, +9141, +2667, +40, +1052, -543, +868, +2094, -1172, -1177, +878, +497, -546, -487, +104, -257, -732, -597, -153, +94, -40, -473, -388, -65, +22, -141, -52, -184, -372, -50, -90, -264,
- +6256, +9830, +2894, -163, +970, -781, +879, +2372, -1514, -1408, +1131, +611, -714, -628, +124, -250, -817, -728, -318, +48, +3, -481, -237, -140, -63, +59, -165, -299, -349, -283, -158, -207,
- +6594, +10538, +3188, -331, +878, -910, +803, +2530, -1667, -1658, +1306, +784, -813, -792, +152, -249, -880, -762, -546, -74, +192, -563, -200, +88, -247, +128, -7, -470, -416, -264, -343, -125,
- +6837, +11211, +3624, -582, +873, -887, +585, +2486, -1630, -1804, +1272, +974, -837, -900, +104, -254, -971, -753, -648, -416, +302, -345, -395, +287, -167, -70, +229, -446, -659, -259, -391, -167,
- +7304, +11778, +3694, -565, +932, -974, +429, +2281, -1610, -1825, +1167, +1061, -833, -962, +48, -273, -1134, -738, -667, -706, +131, -22, -389, +150, +154, -245, +198, -184, -827, -453, -344, -269,
- +8235, +12147, +3165, -179, +1250, -1280, +244, +2247, -1802, -1646, +1035, +1095, -763, -1091, +127, -372, -1161, -866, -623, -801, -185, +121, -30, -44, +248, -32, -42, -16, -686, -726, -403, -227,
- +9297, +12266, +2226, +787, +1787, -2113, +102, +2510, -2139, -1611, +994, +1052, -665, -1269, +199, -511, -1125, -991, -710, -778, -421, -49, +341, +106, +24, +220, -125, -69, -467, -801, -641, -218,
- +10147, +12083, +1353, +2463, +2227, -3535, +293, +3115, -2724, -1863, +1270, +952, -736, -1330, +259, -696, -1131, -995, -849, -797, -533, -301, +461, +439, -103, +301, -72, -178, -379, -650, -774, -450,
- +10811, +11594, +849, +4553, +2308, -5080, +959, +3783, -3596, -2129, +1832, +791, -1018, -1161, +326, -938, -1147, -869, -944, -907, -502, -461, +355, +652, +38, +401, -29, -244, -390, -373, -749, -645,
- +12468, +11803, -955, +4782, +3329, -5109, +523, +3592, -3808, -2001, +2054, +456, -1328, -944, +309, -1271, -1148, -913, -864, -1037, -475, -486, +86, +849, +201, +318, +27, -164, -495, -300, -684, -554,
- +14105, +12174, -2678, +4502, +4313, -4564, -152, +3309, -3818, -1885, +2202, +220, -1631, -822, +354, -1654, -1062, -1037, -689, -1076, -553, -275, -262, +847, +479, +306, -29, -31, -462, -290, -612, -344,
- +15495, +12899, -4263, +3779, +5080, -3531, -900, +2885, -3629, -1828, +2258, +22, -1763, -951, +442, -1975, -1049, -1113, -557, -940, -769, +0, -446, +597, +677, +483, -199, +94, -302, -403, -398, -267,
- +17119, +13318, -5617, +3044, +5263, -2373, -1299, +2236, -3473, -1545, +2114, -220, -1690, -1270, +432, -2146, -1156, -1068, -496, -761, -890, +68, -296, +183, +744, +728, -384, +229, -162, -523, -141, -307,
- +18484, +13996, -6861, +2361, +5043, -1327, -1316, +1482, -3224, -1275, +1889, -488, -1425, -1754, +345, -2172, -1331, -893, -513, -608, -886, +7, -57, -56, +527, +1062, -513, +203, +21, -599, -22, -277,
- +19664, +14808, -7930, +1852, +4472, -629, -944, +743, -2898, -1130, +1684, -714, -1190, -2160, +165, -2109, -1400, -723, -585, -442, -817, -87, +159, -22, +135, +1403, -577, -74, +264, -623, -30, -70,
- +21117, +15043, -8651, +1665, +3562, -302, -433, +306, -2732, -998, +1479, -897, -1082, -2373, -85, -2001, -1270, -757, -612, -253, -784, -73, +231, +244, -130, +1411, -530, -488, +338, -544, +88, +69,
- +22154, +15465, -8959, +1402, +2531, -346, +86, +155, -2719, -964, +1298, -1197, -837, -2538, -368, -1715, -1223, -911, -611, -54, -781, -33, +268, +653, -384, +1073, -318, -957, +90, -192, +241, +104,
- +22859, +15907, -8818, +1234, +1297, -584, +637, +95, -2746, -892, +980, -1473, -344, -2665, -593, -1404, -1232, -1113, -586, +219, -920, +190, +386, +763, -501, +647, -217, -1200, -157, -60, +514, +428,
- +23324, +16162, -8220, +1233, -271, -830, +1044, +4, -2761, -848, +545, -1644, +393, -2819, -805, -1116, -1381, -1232, -481, +245, -798, +446, +127, +832, -496, +109, -143, -1012, -512, -218, +1023, +636,
- +23496, +16326, -7279, +1262, -1985, -1155, +1282, -135, -2863, -819, +135, -1617, +1191, -3031, -953, -1076, -1474, -1177, -641, +567, -852, +321, -9, +770, -595, -103, +21, -1077, -316, -427, +637, +1058,
- +23095, +16685, -5961, +1382, -3468, -1694, +1418, -258, -2996, -670, +47, -1596, +2016, -3064, -1350, -839, -1582, -979, -545, +371, -989, +403, -350, +690, -257, -300, +78, -651, -207, -824, +183, +1360,
- +23064, +16194, -4345, +1405, -4772, -2458, +1309, -309, -3246, -87, -265, -1329, +2641, -3203, -1669, -828, -1062, -1045, -1017, +329, -1074, +156, -379, +809, -266, -110, +348, -721, -327, -460, -318, +476,
- +22166, +16307, -2720, +1513, -5503, -3602, +868, +57, -3167, +189, -262, -1102, +3165, -3419, -1892, +19, -1444, -1300, -1087, -50, -1052, +281, -440, +743, +297, +10, -121, -326, +62, -941, -205, -296,
- +21370, +16040, -1198, +1538, -5866, -4987, +180, +1090, -3147, +120, +48, -770, +2709, -2688, -1726, -511, -1299, -1588, -1418, -44, -787, -13, -172, +1224, -173, +86, +190, -419, +152, -1134, +61, -580,
- +20588, +15763, -447, +2263, -6362, -6502, +294, +1839, -3312, +732, -314, -780, +3610, -2936, -1826, -471, -1919, -1347, -1286, -339, -634, +489, -63, +635, +27, +550, -117, -722, +816, -1169, -430, +0,
- +20517, +14351, +399, +2893, -7361, -6720, +201, +2186, -2610, +382, -514, +112, +3193, -2866, -1734, -1281, -1564, -810, -1919, -87, +325, -151, -301, +1086, -74, +249, +48, -598, +812, -904, -810, +141,
- +19676, +13347, +1269, +2990, -7493, -6742, +83, +2235, -1954, +838, -1855, +980, +3383, -3609, -1607, -1296, -1241, -963, -1499, +306, -188, -169, +134, +680, -311, +474, +114, -498, +603, -657, -632, -512,
- +18294, +12994, +1651, +2477, -6776, -5594, -1193, +2361, -74, -729, -2110, +2060, +2280, -3521, -925, -1755, -1040, +4, -1831, -24, +217, -146, -194, +523, -89, +412, +148, -368, +547, -585, -520, -748,
- +18558, +12123, -346, +2881, -6362, -4645, -59, +1181, -164, -263, -2409, +2048, +1834, -3453, -616, -1525, -435, -206, -2101, +563, +264, -775, -79, +639, -65, +370, -42, -65, +678, -907, -609, -386,
- +17685, +10480, -40, +3473, -6519, -2739, -508, +476, +794, -1230, -2572, +2593, +1476, -3576, +141, -1207, -497, -277, -1926, +798, -90, -892, +128, +624, -265, +467, +194, -122, +569, -901, -567, -322,
- +16309, +9199, +186, +4082, -5385, -2804, -279, +710, -5, -1375, -2021, +2397, +953, -2773, +531, -1321, -456, -212, -1629, +612, -269, -841, +361, +372, -412, +797, +264, -230, +451, -838, -585, -226,
- +15571, +11264, +2379, +478, -10208, -3446, +2999, +3275, -500, -1930, -3348, +266, +1652, -1984, +1186, -362, -580, +611, -665, +483, -71, -639, -236, -683, -414, +551, -551, -99, +973, -315, +229, -109,
- +13108, +11000, +3186, +1280, -8696, -4695, +2112, +2705, +415, -824, -3163, -516, +1162, -1069, +990, -408, -449, +725, -557, +276, +252, -440, -211, -595, -598, +266, -697, +52, +1118, -108, +414, -97,
- +11346, +10103, +3442, +1763, -7242, -4319, +1504, +1898, +542, -443, -2642, -793, +1114, -726, +553, -274, -403, +642, -397, +111, +268, -218, -281, -579, -486, +53, -591, +203, +993, +104, +363, -159,
- +9333, +9181, +4026, +1891, -5737, -3665, +628, +1442, +686, -179, -2080, -924, +1011, -560, +271, -128, -344, +546, -210, +21, +313, -35, -349, -508, -402, +17, -265, +291, +786, +199, +233, -195,
- +7824, +8565, +4450, +1794, -4594, -3174, +140, +1252, +671, +30, -1593, -927, +798, -461, +248, -40, -339, +534, -12, -10, +342, +33, -332, -281, -185, +20, -144, +273, +558, +171, +139, -239,
- +6337, +7830, +4715, +1908, -3553, -2897, -163, +1081, +702, +211, -1249, -839, +616, -437, +196, +111, -267, +479, +135, +12, +326, +212, -47, -34, -177, -218, -105, +167, +266, +120, +84, -158,
- +5342, +7158, +4878, +2188, -2903, -2714, -263, +1026, +804, +276, -973, -621, +425, -432, +323, +229, -177, +523, +156, +236, +666, +314, -37, +11, -270, -439, -68, +145, +155, +196, +77, -226,
- +4764, +6717, +4705, +2043, -2555, -2349, -213, +866, +792, +353, -756, -574, +302, -362, +407, +259, -158, +679, +475, +400, +570, +170, -131, -157, -526, -408, +47, -28, +159, +57, -96, +32,
- +4181, +6120, +4609, +2151, -2225, -2162, -181, +900, +848, +365, -518, -436, +242, -269, +393, +570, +370, +732, +393, +271, +373, -75, -324, -138, -536, -326, +93, -221, -12, +223, +50, -24,
- +4015, +5982, +4273, +1823, -2038, -1791, +35, +933, +871, +389, -235, -337, +148, +75, +824, +806, +274, +455, +265, +150, +178, -130, -231, -188, -435, -270, -151, -8, +202, +32, -30, +38,
- +3935, +5782, +3945, +1507, -1917, -1335, +323, +927, +964, +503, -86, -55, +602, +326, +626, +524, +61, +238, +130, +138, +142, -108, -297, -233, -424, -97, +144, -211, +2, +11, +59, +102,
- +3902, +5745, +3557, +1311, -1656, -1075, +626, +1068, +893, +711, +517, +29, +271, +228, +356, +317, +28, +184, +167, +138, +52, -157, -344, -161, +13, -100, -239, -186, +14, +16, +22, +148,
- +3628, +5656, +3399, +1258, -1213, -703, +858, +1220, +1301, +913, +184, -182, +3, -30, +266, +240, +91, +140, +96, +72, +8, -109, -120, +190, -242, -389, -174, -137, -134, -75, +225, -41,
- +3635, +5627, +3156, +1153, -667, -305, +1152, +1542, +949, +463, +84, -274, -67, -129, +266, +232, +17, +66, +88, +199, -87, +174, +189, -310, -329, -218, -244, -286, -93, -9, -62, +33,
- +3750, +5696, +2978, +1126, -254, +215, +1221, +1141, +606, +286, +8, -220, -48, -224, +233, +223, -143, +120, +323, +31, +156, +458, -282, -324, -203, -336, -370, -173, -80, -307, +26, +219,
- +3708, +6007, +3252, +1084, -197, +131, +973, +976, +487, +259, +136, -370, -69, -106, +43, +210, -33, +247, +171, +273, +554, -86, -293, -37, -371, -530, -251, -143, -337, -184, +155, +321,
- +3943, +6405, +3364, +855, -445, -300, +746, +1177, +555, +245, +158, -422, -186, -48, +127, +143, +129, +192, +83, +689, +384, -278, -109, -102, -392, -521, -225, -363, -322, +86, +221, +118,
- +3963, +6788, +3553, +597, -677, -627, +588, +1136, +500, +391, +206, -514, -153, +22, +70, +197, +285, -39, +123, +985, +227, -286, +1, -155, -441, -352, -267, -542, -311, +209, +364, -112,
- +3772, +6899, +3947, +501, -937, -727, +636, +1168, +340, +109, +160, -312, -140, -4, +244, +180, +122, +45, +73, +884, +451, -250, -58, -111, -413, -290, -294, -523, -289, +122, +331, -74,
- +3462, +6882, +4502, +695, -1202, -904, +656, +1374, +518, -169, -142, -383, -288, +151, +492, +188, +134, +104, -153, +774, +761, -195, -124, +19, -277, -262, -247, -438, -285, +127, +319, -81,
- +3402, +6922, +4775, +801, -1378, -1083, +663, +1537, +602, -245, -249, -453, -540, -124, +493, +404, +124, +134, -71, +426, +838, +18, -287, -73, -153, -110, -193, -451, -296, +175, +269, -23,
- +3560, +7157, +4846, +842, -1601, -1246, +801, +1630, +679, -335, -317, -376, -611, -299, +272, +320, +96, +184, +134, +295, +750, +284, -376, -324, -110, -14, -46, -352, -273, +168, +253, +68,
- +3781, +7518, +5064, +780, -1878, -1426, +861, +1887, +678, -490, -323, -360, -585, -337, +124, +225, -92, -87, +272, +304, +648, +580, -207, -590, -353, -33, +88, -214, -276, +256, +259, +93,
- +4023, +8013, +5260, +520, -2126, -1537, +904, +2110, +621, -684, -367, -338, -545, -334, +31, +151, -90, -326, +98, +316, +484, +602, +136, -551, -624, -186, +88, -177, -281, +258, +226, +119,
- +4437, +8672, +5470, +189, -2426, -1777, +1004, +2534, +471, -984, -417, -281, -536, -313, +40, +69, -119, -424, -33, +239, +301, +445, +325, -371, -639, -347, -13, -119, -335, +161, +141, +68,
- +4952, +9349, +5539, -179, -2758, -2011, +1219, +2888, +279, -1276, -463, -211, -592, -300, +102, -4, -169, -480, -76, +194, +168, +301, +339, -242, -691, -395, -6, -107, -357, +112, +26, -204,
- +5239, +10282, +5947, -647, -3196, -2226, +1311, +3315, +161, -1681, -491, -173, -597, -373, +170, -45, -294, -440, -175, +126, +127, +78, +331, -124, -648, -478, -149, -83, -176, +24, -84, -362,
- +5839, +11149, +6005, -1123, -3665, -2327, +1613, +3627, -71, -2065, -429, -99, -639, -410, +251, -61, -421, -436, -166, +117, +55, -75, +317, -59, -558, -473, -198, -174, -157, +173, -146, -406,
- +6264, +12031, +6260, -1503, -4165, -2511, +1902, +3881, -220, -2443, -428, +51, -706, -495, +320, -9, -559, -492, -144, +113, +44, -260, +228, +46, -480, -381, -268, -203, -217, +218, -114, -429,
- +6813, +12945, +6569, -1945, -4848, -2783, +2188, +4127, -523, -2951, -443, +204, -809, -654, +274, +56, -695, -599, -243, +84, +37, -469, +12, +64, -398, -293, -252, -328, -254, +98, -55, -527,
- +7209, +13717, +6921, -1967, -5316, -3090, +2544, +4308, -606, -3304, -485, +501, -832, -729, +300, +116, -725, -556, -280, +71, +96, -513, -156, +86, -225, -237, -54, -372, -184, +51, -70, -428,
- +7996, +14426, +6885, -1822, -5825, -3511, +3030, +4353, -912, -3620, -593, +764, -830, -921, +358, +119, -837, -534, -312, +44, +63, -481, -430, -53, +49, -227, +88, -308, -219, +114, -168, -425,
- +8882, +15071, +6412, -1835, -5966, -3673, +3408, +4119, -1227, -3662, -763, +899, -746, -1111, +359, +151, -942, -516, -330, +17, -16, -403, -535, -393, +280, -94, +75, -119, -291, +140, -109, -538,
- +10567, +15752, +4909, -1935, -5684, -3567, +3668, +3636, -1744, -3453, -930, +847, -522, -1336, +279, +135, -969, -534, -297, -7, -169, -364, -497, -748, +299, +223, -60, +142, -209, -44, +74, -643,
- +11943, +15859, +3693, -1168, -5342, -4152, +3859, +3672, -2239, -3456, -946, +824, -414, -1484, +211, +82, -987, -499, -174, -100, -272, -362, -415, -898, +70, +599, -127, +237, +12, -204, +166, -634,
- +13286, +15772, +2438, -128, -4984, -4823, +4009, +3750, -2786, -3502, -799, +696, -411, -1556, +156, -56, -1055, -395, +29, -275, -377, -305, -450, -921, -205, +832, -22, +179, +243, -241, +88, -561,
- +15203, +16245, +66, +61, -3930, -4645, +3668, +3392, -3154, -3516, -581, +453, -338, -1692, +34, -193, -1068, -347, +256, -295, -574, -274, -592, -759, -402, +757, +277, +182, +289, -131, -87, -538,
- +17246, +16423, -2122, -11, -3063, -3961, +3236, +2949, -3315, -3590, -360, +310, -300, -1854, +21, -379, -1001, -238, +408, -257, -762, -185, -742, -584, -408, +586, +464, +330, +189, -58, -105, -673,
- +19117, +17194, -4525, -594, -2040, -2928, +2541, +2436, -3174, -3955, -153, +154, -238, -2084, -35, -538, -893, -103, +477, -124, -1066, -60, -862, -458, -281, +408, +389, +584, +66, -198, +49, -844,
- +20721, +17777, -6299, -1368, -1442, -1849, +1965, +2056, -2976, -4357, -43, +20, -202, -2215, -94, -626, -745, -20, +462, +11, -1311, +50, -912, -421, -24, +317, +54, +773, +39, -439, +197, -803,
- +22510, +18390, -7885, -2507, -1141, -610, +1490, +1800, -2821, -4825, -36, -196, -92, -2264, -98, -656, -568, +0, +406, +174, -1496, +186, -1014, -271, +276, +136, -341, +713, +119, -602, +263, -543,
- +23764, +19077, -8920, -3523, -1276, +188, +1429, +1689, -2771, -5201, -193, -427, +128, -2191, -88, -582, -532, -60, +345, +366, -1555, +193, -996, -85, +266, +23, -631, +431, +299, -553, +232, -344,
- +24818, +19733, -9528, -4328, -1918, +770, +1688, +1610, -2757, -5522, -511, -645, +585, -2065, -55, -440, -631, -162, +378, +612, -1616, +251, -901, -119, +151, -32, -905, +195, +543, -403, +171, -190,
- +25942, +20257, -9828, -5006, -3337, +1229, +2251, +1491, -2816, -5884, -1016, -737, +1357, -2026, +75, -408, -894, -120, +477, +717, -1428, +314, -1223, -176, -2, -219, -932, +91, +634, -169, +260, -194,
- +26806, +20370, -9612, -5429, -4920, +1516, +2696, +1428, -3018, -6052, -1361, -633, +1984, -1981, +130, -617, -894, -5, +427, +963, -1258, -100, -1423, -216, -233, -165, -732, -55, +587, +188, +254, -445,
- +27209, +20584, -8793, -5848, -6861, +1389, +3245, +1326, -3300, -5756, -1708, -571, +2761, -2008, -124, -572, -811, +83, +640, +854, -1485, -319, -1727, -286, -130, -52, -610, -82, +598, +192, +317, -394,
- +26893, +21151, -7832, -5916, -8592, +716, +3831, +1043, -3056, -5275, -2081, -436, +3209, -2095, -313, -337, -686, +446, +148, +578, -1361, -677, -1772, -79, -85, -62, -326, -96, +288, +256, +729, -628,
- +26953, +20650, -6193, -5839, -10706, -128, +4025, +1350, -2673, -4655, -2334, -397, +3476, -2270, -280, +333, -640, -63, -135, +292, -1261, -713, -1609, +24, -62, +134, -367, -195, +342, +253, +839, -600,
- +26223, +20702, -4716, -5564, -12304, -1451, +4411, +2099, -2421, -4083, -2432, -598, +3439, -2035, +238, +317, -1138, -105, -496, +286, -908, -750, -1436, +173, -78, -80, -177, -33, +173, +164, +1062, -575,
- +25928, +19969, -3485, -5141, -13936, -2549, +5094, +2717, -2372, -3260, -2726, -1115, +3984, -1704, +8, +193, -1565, -173, -413, +254, -689, -651, -1111, -74, -302, +129, -24, -206, +176, +212, +1048, -582,
- +25176, +19122, -2331, -4479, -15530, -3096, +5493, +3261, -1783, -2862, -3340, -611, +4094, -2064, +150, -498, -1520, +306, -690, +346, -212, -559, -1329, -185, -92, +42, -36, -161, +240, +170, +921, -542,
- +24482, +17970, -1385, -4296, -15673, -3520, +5482, +4107, -1928, -2384, -3245, -840, +4078, -2209, -307, -382, -1158, +232, -617, +670, -229, -809, -1085, -111, -314, +49, +102, -188, +256, +76, +933, -522,
- +23018, +16730, -558, -3503, -15157, -4048, +5380, +4222, -1077, -2064, -4052, -288, +3518, -2565, -42, -296, -1035, +526, -341, +255, -181, -591, -933, -333, -446, +264, +149, -398, +317, +312, +625, -550,
- +21612, +15388, -80, -2338, -14307, -4401, +4806, +4911, -877, -2366, -3925, -404, +3244, -2585, +155, -320, -674, +881, -905, +291, +164, -706, -883, -428, -426, +443, -108, -467, +714, +169, +330, -367,
- +19859, +13489, +594, -510, -13595, -4524, +5021, +4279, -755, -2023, -4414, +179, +2843, -2732, +498, -73, -330, +471, -963, +610, +149, -898, -638, -432, -427, +380, -223, -282, +814, +29, +168, -248,
- +17742, +12321, +1537, +213, -12421, -3676, +4012, +3612, -294, -2291, -3920, +331, +2249, -2515, +892, +37, -643, +510, -767, +581, +11, -855, -358, -539, -531, +491, -270, -331, +960, -123, +115, -173,
- +16821, +11926, +463, -1706, -11380, -169, +5057, +1524, -1492, -1439, -2644, -359, +2193, -2391, +635, +125, -644, +317, -422, +472, -172, -610, -637, -211, -252, -7, -26, -80, -218, -217, +829, -147,
- +13656, +11995, +3238, -883, -11164, -2746, +3338, +2611, +688, -1041, -2888, -1083, +1213, -1539, +1161, +189, -818, +634, -355, +123, +274, -342, -515, +152, -873, -436, -4, -321, +327, +309, +783, -46,
- +11207, +10925, +3942, -83, -8816, -2936, +2399, +2271, +597, -709, -2174, -1110, +823, -992, +937, +143, -694, +584, -237, +52, +375, -217, -303, +162, -792, -361, +105, -252, +214, +381, +632, -19,
- +9243, +9941, +4245, +657, -6939, -2976, +1760, +1792, +578, -304, -1653, -1098, +643, -655, +689, +159, -542, +528, -131, +56, +430, -13, -221, +210, -469, -319, +52, -319, +110, +335, +494, +43,
- +7775, +9004, +4364, +1074, -5566, -2771, +1288, +1356, +632, -19, -1266, -996, +487, -456, +486, +214, -418, +456, -8, +91, +463, +193, -8, +266, -378, -438, -88, -360, -112, +272, +544, +30,
- +6749, +8329, +4226, +1199, -4454, -2378, +954, +1109, +723, +141, -897, -819, +428, -339, +428, +308, -281, +463, +96, +331, +672, +327, +10, +166, -357, -510, -211, -393, -151, +319, +576, +31,
- +5988, +7653, +4116, +1168, -3765, -2038, +743, +915, +737, +259, -623, -668, +285, -262, +442, +295, -206, +564, +342, +402, +543, +169, -105, +70, -443, -594, -251, -433, -272, +334, +502, -77,
- +5467, +7250, +3847, +1019, -3110, -1692, +669, +871, +822, +369, -365, -484, +245, -133, +474, +473, +20, +567, +337, +288, +369, +117, -150, +13, -324, -594, -356, -414, -226, +271, +602, +138,
- +5122, +6973, +3542, +803, -2565, -1389, +713, +947, +893, +463, -170, -291, +235, +82, +633, +446, -49, +345, +308, +240, +201, +133, -77, -9, -324, -573, -352, -476, -45, +494, +363, +16,
- +4855, +6836, +3247, +531, -2098, -1103, +840, +1094, +882, +577, -75, -121, +401, +26, +454, +321, -151, +130, +276, +269, +118, +152, -61, -115, -199, -507, -538, -83, +76, +24, +184, +126,
- +4686, +6807, +3020, +381, -1698, -797, +985, +1300, +880, +654, +193, -260, +327, -18, +295, +312, -217, +5, +244, +427, +89, +60, +69, +22, -305, -328, -97, -385, -172, +69, +91, +154,
- +4632, +6769, +2880, +360, -1379, -630, +1032, +1346, +1008, +601, +155, -416, +54, +91, +208, +254, -266, -94, +300, +314, +94, +118, +154, -112, -59, +83, -557, -570, -137, +42, +28, +65,
- +4540, +6825, +2991, +442, -1145, -666, +903, +1315, +922, +656, +103, -490, -32, -70, +234, +239, -193, -130, +219, +288, +5, +292, +9, +89, +428, -439, -684, -356, -314, -42, +168, -24,
- +4565, +7043, +3133, +398, -1092, -628, +698, +1105, +781, +505, +302, -393, -208, -57, +80, +210, -27, -27, +131, +97, +164, +95, +10, +715, +96, -727, -439, -390, -341, +7, +168, -278,
- +4628, +7376, +3330, +175, -1131, -632, +658, +1096, +468, +306, +276, -396, -10, -64, +41, +226, -104, +83, +212, +65, +61, -40, +256, +815, -181, -624, -368, -423, -196, +109, -11, -411,
- +4617, +7799, +3588, -63, -1282, -806, +761, +1267, +342, +103, +9, -566, -109, +89, +288, +207, -102, +37, +103, +149, +142, -173, +222, +878, -329, -612, -244, -446, -47, +197, -164, -416,
- +4660, +8175, +3965, -277, -1581, -952, +885, +1487, +358, +16, -136, -742, -411, +6, +351, +359, +99, +41, +67, +54, +185, -145, +158, +875, -393, -637, -194, -414, +89, +273, -162, -421,
- +4721, +8663, +4296, -438, -1910, -1208, +1075, +1666, +396, -64, -205, -776, -575, -199, +234, +288, +60, +190, +260, +39, +105, -43, -107, +796, -78, -840, -343, -310, +149, +286, -89, -348,
- +4872, +9194, +4729, -774, -2386, -1225, +1197, +1899, +429, -345, -152, -738, -728, -229, +85, +167, -114, +11, +383, +94, +153, +194, -391, +530, +269, -869, -518, -280, +55, +314, -13, -367,
- +5066, +9823, +5271, -1107, -2955, -1313, +1335, +2152, +396, -624, -133, -598, -828, -241, +24, +42, -162, -203, +299, +184, -39, +336, -145, +68, +454, -442, -819, -503, +69, +300, -63, -319,
- +5153, +10511, +6095, -1484, -3588, -1456, +1423, +2504, +356, -975, -219, -396, -876, -284, +78, -92, -239, -325, +171, +296, -163, +80, +60, -117, +343, +144, -711, -771, -136, +164, +7, -305,
- +5279, +11273, +7005, -1898, -4346, -1576, +1570, +2874, +319, -1413, -325, -192, -896, -360, +145, -111, -363, -399, +61, +261, +19, -193, -117, -56, -9, +423, -34, -872, -482, +162, -138, -388,
- +6056, +12428, +7017, -2743, -5015, -1595, +2092, +3133, -74, -1835, -369, -82, -887, -433, +159, -124, -505, -444, +1, +176, +57, -207, -371, -191, -116, +297, +399, -455, -738, -65, -85, -546,
- +6550, +13417, +7566, -3351, -5854, -1576, +2466, +3359, -262, -2321, -480, +199, -992, -483, +233, -211, -561, -459, -82, +172, +17, -196, -387, -532, -129, +223, +460, +107, -612, -458, -73, -511,
- +7012, +14309, +8271, -3829, -6828, -1561, +2860, +3523, -456, -2805, -697, +575, -1040, -702, +326, -213, -692, -488, -58, +49, +67, -318, -318, -681, -441, +323, +421, +317, -109, -624, -463, -340,
- +8016, +15374, +8120, -4423, -7514, -1497, +3500, +3557, -967, -3143, -754, +778, -1014, -873, +371, -263, -697, -565, +8, +40, -65, -294, -389, -676, -607, +208, +557, +311, +173, -239, -863, -535,
- +8871, +16239, +8063, -4588, -8132, -1638, +4115, +3491, -1344, -3391, -963, +994, -922, -1121, +393, -248, -762, -536, +34, +55, -184, -324, -431, -662, -593, -42, +629, +427, +134, +214, -755, -1041,
- +9741, +17020, +7674, -4576, -8426, -2000, +4611, +3393, -1757, -3551, -1213, +1115, -851, -1378, +299, -217, -824, -499, +46, +51, -282, -489, -415, -741, -447, -171, +355, +641, +79, +272, -284, -1349,
- +11312, +17790, +6362, -4799, -8173, -2096, +4973, +3237, -2301, -3658, -1190, +1112, -886, -1482, +185, -250, -754, -451, +117, +102, -439, -579, -427, -793, -304, +10, -28, +635, +235, +100, +114, -1241,
- +13177, +18485, +4498, -4942, -7590, -1947, +5032, +3048, -2673, -3843, -991, +968, -867, -1596, +107, -286, -639, -361, +165, +232, -672, -529, -499, -772, -195, +286, -298, +389, +407, -34, +287, -927,
- +15061, +19221, +2298, -5197, -6823, -1696, +4782, +2846, -2873, -4171, -778, +660, -800, -1706, -5, -268, -588, -254, +120, +358, -929, -400, -614, -747, -72, +413, -441, -8, +458, -76, +301, -594,
- +17417, +19661, -218, -5533, -6027, -1097, +4358, +2666, -3090, -4449, -601, +308, -686, -1718, -14, -284, -463, -238, +124, +408, -1064, -243, -713, -651, +62, +367, -575, -268, +316, -31, +381, -321,
- +19867, +19942, -2698, -5917, -5419, -356, +3943, +2529, -3315, -4768, -533, -59, -432, -1576, -30, -272, -359, -356, +203, +452, -1089, -118, -778, -495, +49, +184, -640, -440, +103, +121, +489, -151,
- +22000, +20274, -4928, -6244, -5183, +422, +3657, +2387, -3535, -5191, -499, -408, +124, -1486, -39, -209, -489, -410, +327, +558, -1091, -6, -842, -510, -62, +53, -686, -527, +27, +247, +412, +120,
- +23867, +20630, -6764, -6611, -5435, +1219, +3584, +2132, -3790, -5664, -426, -579, +849, -1544, +115, -346, -693, -253, +402, +737, -1086, +70, -1208, -570, -77, -89, -681, -321, -84, +142, +497, +304,
- +25427, +20921, -8048, -7062, -6069, +1884, +3693, +1754, -4141, -5893, -210, -678, +1594, -1604, +126, -548, -678, -23, +392, +982, -1152, -266, -1531, -447, -207, -3, -478, -227, -288, +201, +484, +187,
- +26670, +20956, -8821, -7361, -6968, +2286, +3959, +1161, -4414, -5482, -257, -597, +2261, -1827, +18, -485, -493, +96, +432, +895, -1493, -446, -1665, -450, +33, +175, -509, -150, -228, -15, +349, +351,
- +27247, +21029, -9279, -7221, -8186, +2443, +4316, +433, -4111, -5058, -277, -461, +2624, -2135, +8, -68, -470, +172, -50, +659, -1495, -578, -1725, -94, +295, -26, -297, -74, -411, -173, +430, +303,
- +27900, +20315, -8903, -7184, -9921, +2431, +4704, +385, -3980, -4367, -496, -493, +2857, -2265, +375, +207, -681, -337, -225, +556, -1409, -535, -1534, +66, +228, +14, -233, -136, -400, -267, +410, +268,
- +27607, +19995, -8273, -6960, -11863, +2111, +5727, +206, -3669, -3625, -950, -750, +3372, -2159, +511, +126, -1428, -249, -334, +460, -1027, -385, -1566, +110, +211, -88, -105, -186, -370, -401, +501, +177,
- +27622, +18453, -7307, -6733, -13561, +2585, +6218, +129, -3285, -2980, -1630, -393, +3761, -2468, +529, -441, -1518, +13, -480, +602, -588, -563, -1536, +165, +105, -89, -91, -163, -357, -425, +580, -7,
- +26712, +17271, -6277, -6285, -14362, +2609, +6500, +415, -3110, -2459, -1751, -325, +3747, -2769, +192, -404, -1346, +67, -259, +700, -500, -685, -1381, +215, -122, -46, -21, -142, -291, -476, +628, -31,
- +24769, +16230, -5111, -5257, -14397, +2104, +6670, +474, -2600, -1910, -2144, -355, +3491, -3153, +319, -229, -1416, +584, -304, +502, -383, -651, -1149, -88, -115, +8, -18, -89, -321, -449, +713, -173,
- +22531, +14663, -3328, -4140, -13801, +1449, +6057, +1180, -2109, -1891, -2239, -499, +2901, -2827, +365, -277, -887, +650, -524, +392, -96, -669, -1178, -67, -149, -9, +23, -125, -229, -396, +626, -144,
- +19895, +13154, -1419, -2898, -12707, +438, +5719, +1680, -2070, -1480, -2520, -641, +2754, -2677, +403, +34, -653, +479, -618, +548, -55, -828, -839, -119, -236, +37, -10, -61, -202, -414, +734, -50,
- +15813, +10164, -3306, -1259, -4293, +3357, +1973, -2111, -1944, +200, +219, -308, +1352, -2193, +64, -117, -1126, +153, -436, +60, -137, -521, -663, +805, -86, +19, +120, -674, -64, -483, -254, +28,
- +13540, +9962, -1922, -1329, -4062, +2676, +2356, -1429, -1777, +3, -53, -302, +1192, -1816, -26, +30, -863, +65, -256, +68, -137, -483, -700, +634, +28, +18, +255, -495, -126, -392, -252, -65,
- +11634, +9561, -699, -1265, -3629, +2134, +2474, -898, -1471, -172, -210, -167, +1001, -1414, -33, +173, -616, +55, -78, +97, -92, -391, -629, +503, +182, +60, +264, -359, -148, -296, -278, -94,
- +10116, +9195, +85, -1190, -3168, +1756, +2451, -457, -1159, -296, -215, -72, +824, -1068, +57, +267, -418, +80, +67, +164, -62, -236, -495, +399, +241, +62, +228, -255, -153, -255, -222, -97,
- +8972, +8865, +505, -1212, -2723, +1474, +2315, -138, -916, -335, -184, -65, +679, -767, +131, +280, -267, +100, +140, +232, -22, -124, -428, +222, +224, +45, +106, -204, -143, -199, -220, -223,
- +8143, +8550, +717, -1226, -2288, +1267, +2150, +132, -720, -286, -144, -49, +640, -554, +197, +300, -154, +119, +220, +280, -45, -61, -392, +43, +178, +16, +16, -111, -123, -218, -232, -196,
- +7519, +8353, +812, -1237, -1913, +1117, +2025, +376, -587, -178, -1, -84, +685, -393, +217, +358, -60, +126, +213, +332, -84, -72, -329, -119, +124, +96, -34, -68, -117, -163, -197, -307,
- +7138, +8193, +814, -1279, -1576, +1064, +1902, +541, -519, -85, +237, -175, +678, -205, +145, +407, -22, +33, +193, +347, -106, -168, -290, -132, +40, +147, -63, -81, -15, -226, -137, +56,
- +6765, +8188, +868, -1293, -1277, +1051, +1806, +584, -405, -124, +486, -108, +449, +28, +127, +224, +67, +7, +73, +339, -51, -243, -320, +0, -67, +74, +55, -80, -93, +50, +86, -210,
- +6619, +8107, +942, -1282, -1022, +1117, +1715, +528, -435, -63, +479, +47, +396, -99, +275, +103, -92, +116, +36, +186, -20, -104, -395, -86, -10, +55, +1, -128, +248, +155, -185, -146,
- +6506, +8197, +996, -1294, -821, +1178, +1651, +459, -560, -146, +509, -44, +460, -45, +85, +200, -171, -75, +154, +145, -147, -20, -290, -290, -60, +165, -210, +91, +457, -145, -98, -174,
- +6582, +8378, +972, -1387, -629, +1360, +1678, +371, -630, -289, +430, -31, +347, +59, +235, +84, -170, +9, -19, +188, -18, -105, -290, -206, -28, -83, -58, +442, +120, -133, +100, -328,
- +6729, +8662, +933, -1675, -529, +1529, +1750, +352, -860, -415, +386, -244, +217, +58, +206, +210, -193, -125, +73, +64, -149, +23, -388, -231, +36, -212, +36, +433, -79, -64, +4, -312,
- +6891, +9095, +950, -1986, -500, +1682, +1851, +373, -983, -585, +394, -308, -13, -44, +240, +173, -175, +14, +14, +51, -151, -125, -432, -103, +46, -279, +169, +405, -280, -72, +3, -309,
- +7140, +9633, +936, -2394, -433, +1844, +1940, +403, -1165, -606, +441, -410, -140, -123, +140, +125, -224, -22, +162, +113, -243, -123, -493, -210, +171, -184, +103, +464, -305, -188, -101, -278,
- +7579, +10153, +808, -2790, -377, +2061, +1958, +319, -1378, -620, +599, -484, -299, -248, +140, +31, -407, -65, +163, +117, -205, -114, -553, -215, +158, -225, +53, +587, -241, -398, -127, -310,
- +8098, +10746, +572, -3255, -297, +2282, +1951, +145, -1630, -671, +779, -545, -492, -334, +56, -74, -517, -231, +85, +61, -318, -68, -487, -259, +155, -163, -275, +532, +118, -570, -295, -288,
- +8856, +11416, +228, -3688, -131, +2625, +1937, -65, -1888, -582, +1023, -544, -642, -393, +130, -159, -647, -205, +40, -68, -349, -125, -337, -110, +114, -18, -391, +244, +381, -387, -478, -229,
- +9699, +12034, -166, -4109, -4, +2965, +1853, -341, -2231, -485, +1256, -561, -825, -509, +157, -201, -806, -277, +86, -284, -419, -202, -354, +141, +75, -8, -343, -105, +372, -52, -654, -293,
- +10543, +12775, -545, -4510, +87, +3328, +1796, -636, -2510, -451, +1566, -593, -960, -599, +156, -239, -879, -366, +153, -404, -550, -174, -435, +353, +148, -50, -279, -255, +87, +310, -515, -582,
- +11200, +13601, -758, -4805, +51, +3618, +1817, -936, -2667, -529, +1865, -619, -1077, -658, +152, -290, -948, -411, +137, -381, -707, -102, -513, +487, +276, -91, -256, -301, -183, +365, -56, -808,
- +11970, +14337, -1048, -4982, -71, +3819, +1800, -1224, -2823, -587, +2067, -657, -1227, -698, +129, -342, -1036, -477, +85, -363, -801, -49, -525, +479, +403, -110, -295, -362, -353, +170, +366, -705,
- +12952, +14790, -1411, -4961, -192, +3874, +1746, -1433, -2954, -613, +2172, -717, -1346, -744, +115, -409, -1087, -567, +16, -356, -787, -59, -428, +439, +419, -85, -317, -480, -441, -15, +471, -306,
- +13912, +15283, -1898, -4796, -288, +3733, +1713, -1566, -3031, -703, +2247, -785, -1394, -782, +55, -432, -1125, -661, -51, -311, -721, -96, -300, +422, +338, -39, -314, -612, -519, -71, +296, +100,
- +14855, +15823, -2738, -4516, -305, +3389, +1721, -1674, -3103, -885, +2277, -894, -1325, -878, -28, -456, -1189, -726, -166, -184, -719, -109, -219, +375, +189, +34, -370, -698, -563, -131, +49, +307,
- +16338, +16003, -4097, -3971, -183, +3015, +1641, -1812, -3218, -959, +2300, -1062, -1053, -1052, -10, -553, -1252, -711, -213, -61, -766, +9, -305, +359, +93, +64, -446, -677, -520, -329, -54, +380,
- +18251, +15738, -5808, -3185, -135, +2789, +1385, -1959, -3407, -901, +2346, -1243, -701, -1229, +42, -723, -1269, -588, -226, -66, -699, +25, -533, +532, -57, +38, -378, -632, -576, -478, +14, +227,
- +20108, +15232, -7463, -2359, -182, +2680, +993, -2135, -3628, -757, +2465, -1466, -282, -1397, +30, -889, -1150, -413, -456, +70, -740, -222, -483, +617, -261, +207, -289, -809, -541, -427, -149, +45,
- +21818, +14565, -8920, -1528, -323, +2633, +590, -2360, -3741, -408, +2485, -1626, +257, -1681, +37, -834, -979, -443, -529, +77, -986, -154, -547, +693, -157, +334, -410, -839, -327, -606, -328, +75,
- +23103, +13939, -10069, -743, -746, +2659, +301, -2677, -3587, -100, +2394, -1612, +709, -2069, +297, -672, -1108, -278, -883, +30, -908, -351, -497, +1045, -177, +252, -316, -804, -379, -726, -359, +57,
- +23945, +13086, -10548, -173, -1474, +2865, +166, -2907, -3401, +227, +2202, -1525, +1022, -2203, +552, -677, -1107, -549, -996, +157, -1089, -304, -261, +1165, -310, +418, -308, -941, -344, -785, -396, +51,
- +24255, +12118, -10245, -13, -2426, +3265, +310, -3204, -3183, +647, +1733, -1352, +1565, -2480, +734, -599, -1582, -399, -1019, +24, -846, -257, -242, +1202, -199, +374, -346, -1003, -311, -777, -466, +127,
- +23709, +11520, -9531, -151, -3388, +3855, +550, -3483, -2789, +731, +1250, -841, +1752, -2633, +801, -862, -1583, -318, -1087, +206, -657, -373, -274, +1353, -271, +302, -334, -1032, -204, -865, -432, +235,
- +22428, +11143, -8405, -496, -4041, +4230, +889, -3448, -2615, +728, +1070, -660, +1947, -2748, +486, -621, -1697, -171, -896, +282, -583, -459, -269, +1324, -316, +161, -148, -1048, -191, -833, -297, +216,
- +20761, +10556, -6721, -940, -4366, +4259, +1328, -3270, -2442, +888, +519, -254, +1808, -2851, +481, -564, -1534, -32, -625, +157, -458, -456, -349, +1175, -358, +206, -68, -1025, -144, -651, -305, +204,
- +18483, +10322, -5051, -1232, -4488, +3998, +1699, -2851, -2083, +521, +346, -174, +1484, -2533, +230, -316, -1365, +115, -496, +12, -245, -474, -558, +987, -219, +124, +13, -912, -46, -573, -264, +159,
- +15151, +10407, -3905, -1083, -1883, +2118, +367, -2185, -1952, +542, +790, -175, +1158, -1491, +303, +11, -942, -141, -277, +14, -417, -305, -403, +619, -260, -27, +128, -617, -289, -452, -406, -109,
- +12885, +10154, -2446, -1435, -1886, +1994, +819, -1625, -1685, +115, +676, -116, +950, -1122, +70, +152, -656, +7, -100, +33, -249, -339, -518, +467, -154, -64, +221, -437, -240, -376, -360, -167,
- +11026, +9815, -1373, -1604, -1732, +1727, +1082, -1042, -1489, -153, +594, -120, +851, -783, -35, +259, -348, +25, +24, +163, -205, -275, -535, +286, -60, -104, +181, -299, -203, -314, -276, -258,
- +9638, +9479, -718, -1704, -1525, +1463, +1205, -627, -1291, -289, +532, -105, +728, -476, -29, +265, -147, +9, +102, +238, -168, -228, -548, +99, -70, -181, +55, -160, -166, -274, -267, -318,
- +8752, +9179, -333, -1745, -1266, +1296, +1255, -331, -1103, -308, +517, +6, +654, -256, +108, +218, -57, +66, +139, +248, -132, -162, -550, -73, -107, -216, +35, -13, -164, -279, -126, -282,
- +8140, +9001, -85, -1784, -995, +1204, +1247, -134, -1072, -291, +536, +70, +685, -204, +206, +280, -165, +40, +195, +187, -211, -72, -529, -292, -102, -127, -36, -76, -58, -138, -270, -89,
- +7821, +8936, +29, -1810, -714, +1265, +1138, -40, -1096, -420, +649, +5, +642, -11, +138, +306, -111, -183, +147, +285, -330, -213, -387, -248, -250, -102, -97, -86, +22, -265, +130, +187,
- +7807, +9028, -50, -1866, -441, +1451, +1138, -195, -1118, -490, +518, +2, +517, +35, +307, +254, -153, -103, +7, +126, -244, -245, -496, -140, -99, -332, -144, +49, -205, +61, +387, -266,
- +7883, +9354, -84, -2058, -175, +1671, +1191, -268, -1313, -554, +542, -204, +353, +81, +268, +401, -95, -139, +119, +41, -495, -190, -362, -215, -155, -154, -74, -308, -29, +393, -17, -331,
- +8309, +9731, -294, -2293, +42, +1934, +1203, -363, -1445, -664, +574, -270, +131, -85, +298, +391, -163, +29, +228, -28, -529, -302, -516, -77, -71, -224, -65, -236, +37, +234, -157, -305,
- +8910, +10272, -662, -2606, +320, +2118, +1145, -521, -1640, -652, +647, -370, -95, -197, +260, +249, -276, +1, +311, +7, -540, -340, -597, -115, -162, -109, -41, -330, +23, +288, -224, -561,
- +9705, +10883, -1159, -2876, +618, +2308, +939, -735, -1827, -569, +847, -551, -252, -350, +282, +190, -540, -53, +297, -89, -533, -247, -636, +1, -229, -304, +0, -239, -164, +169, +30, -627,
- +10729, +11542, -1791, -3053, +931, +2475, +682, -1055, -1976, -419, +1145, -742, -457, -399, +293, +130, -657, -195, +215, -136, -668, -129, -569, +112, -117, -431, -109, -273, -261, +33, +231, -480,
- +11880, +12255, -2434, -3089, +1163, +2572, +450, -1357, -2085, -232, +1467, -892, -621, -438, +381, +30, -732, -214, +65, -162, -709, -100, -437, +212, -28, -368, -165, -380, -411, -90, +291, -64,
- +13138, +12910, -3157, -3037, +1198, +2492, +221, -1627, -2212, -103, +1693, -1094, -727, -513, +408, -69, -857, -306, -36, -187, -773, -78, -367, +223, -33, -259, -244, -476, -574, -270, +164, +260,
- +14397, +13579, -3910, -2827, +1090, +2265, +96, -1784, -2287, -52, +1872, -1249, -736, -567, +401, -118, -956, -410, -92, -132, -795, +4, -347, +213, -84, -122, -283, -544, -622, -487, +74, +387,
- +15830, +13982, -4898, -2472, +856, +1874, -58, -1916, -2412, -69, +1931, -1394, -672, -679, +358, -219, -1064, -512, -131, -146, -801, +55, -460, +223, -217, -78, -273, -623, -663, -737, +48, +327,
- +17467, +14082, -6145, -1897, +641, +1483, -284, -1985, -2544, -62, +2082, -1574, -443, -758, +315, -348, -1052, -474, -316, -34, -792, -77, -456, +264, -381, +42, -169, -787, -651, -765, -87, +204,
- +19204, +13692, -7428, -1120, +469, +1144, -634, -1991, -2737, +205, +2197, -1785, +24, -916, +275, -357, -852, -637, -399, +114, -1061, -13, -468, +245, -296, +208, -219, -909, -451, -819, -365, +209,
- +20434, +13223, -8548, -342, +182, +828, -924, -2160, -2725, +468, +2161, -1789, +445, -1242, +435, -205, -999, -575, -649, -4, -1029, -158, -482, +542, -293, +181, -169, -874, -514, -927, -442, +127,
- +21071, +12403, -8865, +245, -318, +823, -1130, -2243, -2635, +724, +2101, -1684, +725, -1293, +626, -269, -883, -830, -829, +105, -1203, -105, -238, +653, -371, +371, -143, -1016, -532, -886, -493, +33,
- +20789, +11662, -8363, +332, -911, +1138, -984, -2430, -2493, +1026, +1715, -1379, +1228, -1581, +803, -170, -1256, -633, -926, +9, -905, -125, -208, +782, -256, +313, -208, -993, -501, -825, -526, -5,
- +19596, +11016, -7150, -54, -1442, +1677, -696, -2554, -2277, +940, +1405, -817, +1246, -1536, +683, -288, -1142, -645, -762, +96, -739, -256, -171, +923, -379, +209, -146, -915, -439, -791, -471, +64,
- +17572, +10705, -5607, -659, -1779, +2017, -199, -2475, -2231, +834, +1110, -554, +1413, -1693, +462, -69, -1229, -319, -565, +61, -598, -344, -187, +729, -361, +89, -38, -790, -417, -617, -384, -60,
- +13984, +10256, -4374, -387, +520, +1170, -465, -1651, -1737, +620, +1299, -598, +593, -692, +507, -106, -759, -500, -601, +13, -482, -134, -166, +603, -169, +64, -79, -688, -462, -543, -415, -231,
- +12758, +10312, -3687, -1357, +269, +1735, +98, -1444, -1892, +26, +1171, -327, +678, -523, +452, +210, -645, -277, -231, -18, -408, -233, -377, +567, -155, -104, +72, -516, -401, -434, -355, -174,
- +11716, +10426, -3021, -2050, -38, +1840, +528, -1068, -1835, -336, +989, -214, +710, -348, +420, +365, -440, -231, -16, +39, -429, -185, -574, +332, -35, -237, +26, -307, -370, -373, -221, -235,
- +11134, +10529, -2662, -2372, -80, +1872, +687, -929, -1758, -466, +868, -263, +670, -278, +447, +463, -382, -147, +37, -28, -515, -135, -648, +44, +50, -206, -64, -271, -287, -346, -196, -161,
- +11076, +10636, -2726, -2397, +319, +2006, +654, -1075, -1802, -427, +898, -371, +393, -170, +406, +444, -274, -100, +119, -97, -686, -259, -554, +17, -61, -105, -68, -278, -240, -444, -157, +31,
- +11612, +10554, -3129, -2035, +925, +2135, +343, -1322, -1834, -253, +981, -508, +127, -339, +524, +263, -428, +146, +113, -216, -691, -403, -615, +161, -3, -171, -98, -195, -334, -500, -145, +70,
- +12375, +10683, -3543, -1496, +1375, +1878, -63, -1524, -1717, +100, +1163, -755, -161, -335, +443, +21, -544, +0, +88, -275, -693, -316, -565, +159, -85, -8, -150, -333, -390, -555, -137, +51,
- +13451, +11029, -4018, -1046, +1272, +1286, -363, -1499, -1496, +592, +1316, -1108, -273, -352, +296, -275, -635, -344, -118, -175, -740, -127, -424, +105, -164, +113, -179, -568, -399, -627, -271, +78,
- +14734, +11620, -4801, -879, +695, +632, -389, -1350, -1318, +1007, +1424, -1500, -74, -505, -4, -282, -945, -711, -166, -124, -792, +39, -391, +77, -83, +118, -326, -662, -381, -867, -393, +164,
- +15985, +11630, -5516, -532, +203, +208, -354, -1214, -1189, +1341, +1442, -1615, +268, -744, -62, -254, -1183, -868, -259, -11, -770, +72, -261, +154, +24, +109, -377, -617, -514, -967, -389, +157,
- +16167, +11377, -5735, -169, +103, +84, -542, -1299, -1254, +1362, +1544, -1556, +422, -670, -103, -248, -1015, -1157, -377, +88, -926, +197, -106, +201, +13, +190, -354, -777, -517, -923, -458, +58,
- +15468, +10670, -5248, +0, +346, +442, -693, -1493, -1502, +1200, +1468, -1209, +625, -745, +218, -158, -964, -895, -623, +11, -688, +93, -44, +335, -4, +183, -327, -757, -508, -710, -494, -108,
- +11864, +10338, -3078, -621, +1333, +599, -268, -1143, -1003, +1077, +1244, -764, -17, -195, +147, -60, -510, -758, -332, -70, -719, -16, -15, +316, +287, +250, -355, -886, -747, -549, -54, +215,
-};
-
-/* HRIR Delays */
-static const ALubyte defaultDelays[828] =
-{
- 12, 12, 13, 14, 14, 14, 13, 12, 11, 10, 10, 10, 11, 12, 13, 14, 15, 15, 16, 16, 16, 15, 15, 14, 13, 12, 11, 10, 9, 8, 8, 8, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 18, 18, 18, 18, 18, 17, 16, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 7, 6, 6, 6, 6, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 19, 20, 20, 20, 20, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 8, 7, 6, 5, 5, 5, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 21, 22, 22, 22, 22, 22, 21, 21, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 22, 23, 24, 24, 24, 24, 24, 23, 22, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 24, 25, 26, 26, 26, 26, 26, 25, 24, 24, 23, 22, 21, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 28, 28, 27, 26, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 28, 28, 27, 26, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 24, 25, 26, 26, 26, 26, 26, 25, 24, 24, 23, 22, 21, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 22, 23, 24, 24, 24, 24, 24, 23, 22, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 21, 22, 22, 22, 22, 22, 21, 21, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 19, 20, 20, 20, 20, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 8, 7, 6, 5, 5, 5, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 18, 18, 18, 18, 18, 17, 16, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 7, 6, 6, 6, 6, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 16, 16, 16, 15, 15, 14, 13, 12, 11, 10, 9, 8, 8, 8, 8, 8, 9, 10, 11, 12, 13, 14, 14, 14, 13, 12, 11, 10, 10, 10, 11, 12,
-};
-
-/* Default HRTF Definition */
-static const struct Hrtf DefaultHrtf = {
- 44100, 32, 19, defaultAzCount, defaultEvOffset,
- defaultCoeffs, defaultDelays, NULL
-};
diff --git a/Alc/midi/base.h b/Alc/midi/base.h
index 4d13a054..42a4c279 100644
--- a/Alc/midi/base.h
+++ b/Alc/midi/base.h
@@ -80,7 +80,6 @@ struct MidiSynthVtable {
ALenum (*const selectSoundfonts)(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
void (*const setGain)(MidiSynth *self, ALfloat gain);
- void (*const setState)(MidiSynth *self, ALenum state);
void (*const stop)(MidiSynth *self);
void (*const reset)(MidiSynth *self);
@@ -88,26 +87,25 @@ struct MidiSynthVtable {
void (*const update)(MidiSynth *self, ALCdevice *device);
void (*const process)(MidiSynth *self, ALuint samples, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
- void (*const Delete)(MidiSynth *self);
+ void (*const Delete)(void *ptr);
};
#define DEFINE_MIDISYNTH_VTABLE(T) \
DECLARE_THUNK(T, MidiSynth, void, Destruct) \
DECLARE_THUNK3(T, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*) \
DECLARE_THUNK1(T, MidiSynth, void, setGain, ALfloat) \
-DECLARE_THUNK1(T, MidiSynth, void, setState, ALenum) \
DECLARE_THUNK(T, MidiSynth, void, stop) \
DECLARE_THUNK(T, MidiSynth, void, reset) \
DECLARE_THUNK1(T, MidiSynth, void, update, ALCdevice*) \
DECLARE_THUNK2(T, MidiSynth, void, process, ALuint, ALfloatBUFFERSIZE*restrict) \
-DECLARE_THUNK(T, MidiSynth, void, Delete) \
+static void T##_MidiSynth_Delete(void *ptr) \
+{ T##_Delete(STATIC_UPCAST(T, MidiSynth, (MidiSynth*)ptr)); } \
\
static const struct MidiSynthVtable T##_MidiSynth_vtable = { \
T##_MidiSynth_Destruct, \
\
T##_MidiSynth_selectSoundfonts, \
T##_MidiSynth_setGain, \
- T##_MidiSynth_setState, \
T##_MidiSynth_stop, \
T##_MidiSynth_reset, \
T##_MidiSynth_update, \
@@ -117,6 +115,7 @@ static const struct MidiSynthVtable T##_MidiSynth_vtable = { \
}
+MidiSynth *SSynth_create(ALCdevice *device);
MidiSynth *FSynth_create(ALCdevice *device);
MidiSynth *DSynth_create(ALCdevice *device);
diff --git a/Alc/midi/dummy.c b/Alc/midi/dummy.c
index 79f82b87..d50b8fef 100644
--- a/Alc/midi/dummy.c
+++ b/Alc/midi/dummy.c
@@ -22,12 +22,11 @@ static void DSynth_Construct(DSynth *self, ALCdevice *device);
static DECLARE_FORWARD(DSynth, MidiSynth, void, Destruct)
static DECLARE_FORWARD3(DSynth, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*)
static DECLARE_FORWARD1(DSynth, MidiSynth, void, setGain, ALfloat)
-static DECLARE_FORWARD1(DSynth, MidiSynth, void, setState, ALenum)
static DECLARE_FORWARD(DSynth, MidiSynth, void, stop)
static DECLARE_FORWARD(DSynth, MidiSynth, void, reset)
static DECLARE_FORWARD1(DSynth, MidiSynth, void, update, ALCdevice*)
static void DSynth_process(DSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
-static void DSynth_Delete(DSynth *self);
+DECLARE_DEFAULT_ALLOCATORS(DSynth)
DEFINE_MIDISYNTH_VTABLE(DSynth);
@@ -63,20 +62,15 @@ static void DSynth_process(DSynth *self, ALuint SamplesToDo, ALfloatBUFFERSIZE*r
}
-static void DSynth_Delete(DSynth *self)
-{
- free(self);
-}
-
-
MidiSynth *DSynth_create(ALCdevice *device)
{
- DSynth *synth = calloc(1, sizeof(*synth));
+ DSynth *synth = DSynth_New(sizeof(*synth));
if(!synth)
{
ERR("Failed to allocate DSynth\n");
return NULL;
}
+ memset(synth, 0, sizeof(*synth));
DSynth_Construct(synth, device);
return STATIC_CAST(MidiSynth, synth);
}
diff --git a/Alc/midi/fluidsynth.c b/Alc/midi/fluidsynth.c
index d4e594e6..b4788635 100644
--- a/Alc/midi/fluidsynth.c
+++ b/Alc/midi/fluidsynth.c
@@ -470,13 +470,12 @@ static void FSynth_Destruct(FSynth *self);
static ALboolean FSynth_init(FSynth *self, ALCdevice *device);
static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
static void FSynth_setGain(FSynth *self, ALfloat gain);
-static void FSynth_setState(FSynth *self, ALenum state);
static void FSynth_stop(FSynth *self);
static void FSynth_reset(FSynth *self);
static void FSynth_update(FSynth *self, ALCdevice *device);
static void FSynth_processQueue(FSynth *self, ALuint64 time);
static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
-static void FSynth_Delete(FSynth *self);
+DECLARE_DEFAULT_ALLOCATORS(FSynth)
DEFINE_MIDISYNTH_VTABLE(FSynth);
static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename);
@@ -632,11 +631,6 @@ static void FSynth_setGain(FSynth *self, ALfloat gain)
}
-static void FSynth_setState(FSynth *self, ALenum state)
-{
- MidiSynth_setState(STATIC_CAST(MidiSynth, self), state);
-}
-
static void FSynth_stop(FSynth *self)
{
MidiSynth *synth = STATIC_CAST(MidiSynth, self);
@@ -798,20 +792,15 @@ static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict
}
-static void FSynth_Delete(FSynth *self)
-{
- free(self);
-}
-
-
MidiSynth *FSynth_create(ALCdevice *device)
{
- FSynth *synth = calloc(1, sizeof(*synth));
+ FSynth *synth = FSynth_New(sizeof(*synth));
if(!synth)
{
ERR("Failed to allocate FSynth\n");
return NULL;
}
+ memset(synth, 0, sizeof(*synth));
FSynth_Construct(synth, device);
if(FSynth_init(synth, device) == AL_FALSE)
diff --git a/Alc/midi/sf2load.c b/Alc/midi/sf2load.c
index 169a5189..2bc94133 100644
--- a/Alc/midi/sf2load.c
+++ b/Alc/midi/sf2load.c
@@ -50,9 +50,10 @@ static void skip(Reader *stream, ALuint amt)
size_t got;
got = READ(stream, buf, minu(sizeof(buf), amt));
- if(got == 0) READERR(stream) = 1;
+ if(got == 0 || got > amt)
+ READERR(stream) = 1;
- amt -= got;
+ amt -= (ALuint)got;
}
}
@@ -324,61 +325,46 @@ static void RiffHdr_read(RiffHdr *self, Reader *stream)
}
-typedef struct GenModList {
- Generator *gens;
- ALsizei gens_size;
- ALsizei gens_max;
+DECL_VECTOR(Generator)
+DECL_VECTOR(Modulator)
- Modulator *mods;
- ALsizei mods_size;
- ALsizei mods_max;
+typedef struct GenModList {
+ vector_Generator gens;
+ vector_Modulator mods;
} GenModList;
static void GenModList_Construct(GenModList *self)
{
- self->gens = NULL;
- self->gens_size = 0;
- self->gens_max = 0;
-
- self->mods = NULL;
- self->mods_size = 0;
- self->mods_max = 0;
+ VECTOR_INIT(self->gens);
+ VECTOR_INIT(self->mods);
}
static void GenModList_Destruct(GenModList *self)
{
- free(self->gens);
- self->gens = NULL;
- self->gens_size = 0;
- self->gens_max = 0;
-
- free(self->mods);
- self->mods = NULL;
- self->mods_size = 0;
- self->mods_max = 0;
+ VECTOR_DEINIT(self->mods);
+ VECTOR_DEINIT(self->gens);
}
static GenModList GenModList_clone(const GenModList *self)
{
GenModList ret;
- ret.gens = malloc(self->gens_max * sizeof(ret.gens[0]));
- memcpy(ret.gens, self->gens, self->gens_size * sizeof(ret.gens[0]));
- ret.gens_size = self->gens_size;
- ret.gens_max = self->gens_max;
+ GenModList_Construct(&ret);
- ret.mods = malloc(self->mods_max * sizeof(ret.mods[0]));
- memcpy(ret.mods, self->mods, self->mods_size * sizeof(ret.mods[0]));
- ret.mods_size = self->mods_size;
- ret.mods_max = self->mods_max;
+ VECTOR_INSERT(ret.gens, VECTOR_ITER_END(ret.gens),
+ VECTOR_ITER_BEGIN(self->gens), VECTOR_ITER_END(self->gens)
+ );
+ VECTOR_INSERT(ret.mods, VECTOR_ITER_END(ret.mods),
+ VECTOR_ITER_BEGIN(self->mods), VECTOR_ITER_END(self->mods)
+ );
return ret;
}
static void GenModList_insertGen(GenModList *self, const Generator *gen, ALboolean ispreset)
{
- Generator *i = self->gens;
- Generator *end = i + self->gens_size;
+ Generator *i = VECTOR_ITER_BEGIN(self->gens);
+ Generator *end = VECTOR_ITER_END(self->gens);
for(;i != end;i++)
{
if(i->mGenerator == gen->mGenerator)
@@ -396,32 +382,16 @@ static void GenModList_insertGen(GenModList *self, const Generator *gen, ALboole
gen->mGenerator == 58))
return;
- if(self->gens_size == self->gens_max)
+ if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE)
{
- void *temp = NULL;
- ALsizei newsize;
-
- newsize = (self->gens_max ? self->gens_max<<1 : 1);
- if(newsize > self->gens_max)
- temp = realloc(self->gens, newsize * sizeof(self->gens[0]));
- if(!temp)
- {
- ERR("Failed to increase generator storage to %d elements (from %d)\n",
- newsize, self->gens_max);
- return;
- }
-
- self->gens = temp;
- self->gens_max = newsize;
+ ERR("Failed to insert generator (from %d elements)\n", VECTOR_SIZE(self->gens));
+ return;
}
-
- self->gens[self->gens_size] = *gen;
- self->gens_size++;
}
static void GenModList_accumGen(GenModList *self, const Generator *gen)
{
- Generator *i = self->gens;
- Generator *end = i + self->gens_size;
+ Generator *i = VECTOR_ITER_BEGIN(self->gens);
+ Generator *end = VECTOR_ITER_END(self->gens);
for(;i != end;i++)
{
if(i->mGenerator == gen->mGenerator)
@@ -441,35 +411,19 @@ static void GenModList_accumGen(GenModList *self, const Generator *gen)
}
}
- if(self->gens_size == self->gens_max)
+ if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE)
{
- void *temp = NULL;
- ALsizei newsize;
-
- newsize = (self->gens_max ? self->gens_max<<1 : 1);
- if(newsize > self->gens_max)
- temp = realloc(self->gens, newsize * sizeof(self->gens[0]));
- if(!temp)
- {
- ERR("Failed to increase generator storage to %d elements (from %d)\n",
- newsize, self->gens_max);
- return;
- }
-
- self->gens = temp;
- self->gens_max = newsize;
+ ERR("Failed to insert generator (from %d elements)\n", VECTOR_SIZE(self->gens));
+ return;
}
-
- self->gens[self->gens_size] = *gen;
if(gen->mGenerator < 60)
- self->gens[self->gens_size].mAmount += DefaultGenValue[gen->mGenerator];
- self->gens_size++;
+ VECTOR_BACK(self->gens).mAmount += DefaultGenValue[gen->mGenerator];
}
static void GenModList_insertMod(GenModList *self, const Modulator *mod)
{
- Modulator *i = self->mods;
- Modulator *end = i + self->mods_size;
+ Modulator *i = VECTOR_ITER_BEGIN(self->mods);
+ Modulator *end = VECTOR_ITER_END(self->mods);
for(;i != end;i++)
{
if(i->mDstOp == mod->mDstOp && i->mSrcOp == mod->mSrcOp &&
@@ -480,32 +434,16 @@ static void GenModList_insertMod(GenModList *self, const Modulator *mod)
}
}
- if(self->mods_size == self->mods_max)
+ if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE)
{
- void *temp = NULL;
- ALsizei newsize;
-
- newsize = (self->mods_max ? self->mods_max<<1 : 1);
- if(newsize > self->mods_max)
- temp = realloc(self->mods, newsize * sizeof(self->mods[0]));
- if(!temp)
- {
- ERR("Failed to increase modulator storage to %d elements (from %d)\n",
- newsize, self->mods_max);
- return;
- }
-
- self->mods = temp;
- self->mods_max = newsize;
+ ERR("Failed to insert modulator (from %d elements)\n", VECTOR_SIZE(self->mods));
+ return;
}
-
- self->mods[self->mods_size] = *mod;
- self->mods_size++;
}
static void GenModList_accumMod(GenModList *self, const Modulator *mod)
{
- Modulator *i = self->mods;
- Modulator *end = i + self->mods_size;
+ Modulator *i = VECTOR_ITER_BEGIN(self->mods);
+ Modulator *end = VECTOR_ITER_END(self->mods);
for(;i != end;i++)
{
if(i->mDstOp == mod->mDstOp && i->mSrcOp == mod->mSrcOp &&
@@ -516,47 +454,32 @@ static void GenModList_accumMod(GenModList *self, const Modulator *mod)
}
}
- if(self->mods_size == self->mods_max)
+ if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE)
{
- void *temp = NULL;
- ALsizei newsize;
-
- newsize = (self->mods_max ? self->mods_max<<1 : 1);
- if(newsize > self->mods_max)
- temp = realloc(self->mods, newsize * sizeof(self->mods[0]));
- if(!temp)
- {
- ERR("Failed to increase modulator storage to %d elements (from %d)\n",
- newsize, self->mods_max);
- return;
- }
-
- self->mods = temp;
- self->mods_max = newsize;
+ ERR("Failed to insert modulator (from %d elements)\n", VECTOR_SIZE(self->mods));
+ return;
}
- self->mods[self->mods_size] = *mod;
if(mod->mSrcOp == 0x0502 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- self->mods[self->mods_size].mAmount += 960;
+ VECTOR_BACK(self->mods).mAmount += 960;
else if(mod->mSrcOp == 0x0102 && mod->mDstOp == 8 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- self->mods[self->mods_size].mAmount += -2400;
+ VECTOR_BACK(self->mods).mAmount += -2400;
else if(mod->mSrcOp == 0x000D && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- self->mods[self->mods_size].mAmount += 50;
+ VECTOR_BACK(self->mods).mAmount += 50;
else if(mod->mSrcOp == 0x0081 && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- self->mods[self->mods_size].mAmount += 50;
+ VECTOR_BACK(self->mods).mAmount += 50;
else if(mod->mSrcOp == 0x0582 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- self->mods[self->mods_size].mAmount += 960;
+ VECTOR_BACK(self->mods).mAmount += 960;
else if(mod->mSrcOp == 0x028A && mod->mDstOp == 17 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- self->mods[self->mods_size].mAmount += 1000;
+ VECTOR_BACK(self->mods).mAmount += 1000;
else if(mod->mSrcOp == 0x058B && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- self->mods[self->mods_size].mAmount += 960;
+ VECTOR_BACK(self->mods).mAmount += 960;
else if(mod->mSrcOp == 0x00DB && mod->mDstOp == 16 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- self->mods[self->mods_size].mAmount += 200;
+ VECTOR_BACK(self->mods).mAmount += 200;
else if(mod->mSrcOp == 0x00DD && mod->mDstOp == 15 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- self->mods[self->mods_size].mAmount += 200;
+ VECTOR_BACK(self->mods).mAmount += 200;
/*else if(mod->mSrcOp == 0x020E && mod->mDstOp == ?initialpitch? && mod->mAmtSrcOp == 0x0010 && mod->mTransOp == 0)
- self->mods[self->mods_size].mAmount += 12700;*/
- self->mods_size++;
+ VECTOR_BACK(self->mods).mAmount += 12700;*/
}
@@ -710,21 +633,21 @@ static ALboolean ensureFontSanity(const Soundfont *sfont)
static ALboolean checkZone(const GenModList *zone, const PresetHeader *preset, const InstrumentHeader *inst, const SampleHeader *samp)
{
- ALsizei i;
-
- for(i = 0;i < zone->gens_size;i++)
+ Generator *gen = VECTOR_ITER_BEGIN(zone->gens);
+ Generator *gen_end = VECTOR_ITER_END(zone->gens);
+ for(;gen != gen_end;gen++)
{
- if(zone->gens[i].mGenerator == 43 || zone->gens[i].mGenerator == 44)
+ if(gen->mGenerator == 43 || gen->mGenerator == 44)
{
- int high = zone->gens[i].mAmount>>8;
- int low = zone->gens[i].mAmount&0xff;
+ int high = gen->mAmount>>8;
+ int low = gen->mAmount&0xff;
if(!(low >= 0 && high <= 127 && high >= low))
{
TRACE("Preset \"%s\", inst \"%s\", sample \"%s\": invalid %s range %d...%d\n",
preset->mName, inst->mName, samp->mName,
- (zone->gens[i].mGenerator == 43) ? "key" :
- (zone->gens[i].mGenerator == 44) ? "velocity" : "(unknown)",
+ (gen->mGenerator == 43) ? "key" :
+ (gen->mGenerator == 44) ? "velocity" : "(unknown)",
low, high);
return AL_FALSE;
}
@@ -871,43 +794,43 @@ static void fillZone(ALfontsound *sound, ALCcontext *context, const GenModList *
0, /* 59 - */
};
const Generator *gen, *gen_end;
+ const Modulator *mod, *mod_end;
- if(zone->mods)
+ mod = VECTOR_ITER_BEGIN(zone->mods);
+ mod_end = VECTOR_ITER_END(zone->mods);
+ for(;mod != mod_end;mod++)
{
- ALsizei i;
- for(i = 0;i < zone->mods_size;i++)
+ ALenum src0in = getModSrcInput(mod->mSrcOp&0xFF);
+ ALenum src0type = getModSrcType(mod->mSrcOp&0x0300);
+ ALenum src0form = getModSrcForm(mod->mSrcOp&0xFC00);
+ ALenum src1in = getModSrcInput(mod->mAmtSrcOp&0xFF);
+ ALenum src1type = getModSrcType(mod->mAmtSrcOp&0x0300);
+ ALenum src1form = getModSrcForm(mod->mAmtSrcOp&0xFC00);
+ ALenum trans = getModTransOp(mod->mTransOp);
+ ALenum dst = (mod->mDstOp < 60) ? Gen2Param[mod->mDstOp] : 0;
+ if(!dst || dst == AL_KEY_RANGE_SOFT || dst == AL_VELOCITY_RANGE_SOFT ||
+ dst == AL_LOOP_MODE_SOFT || dst == AL_EXCLUSIVE_CLASS_SOFT ||
+ dst == AL_BASE_KEY_SOFT)
+ ERR("Unhandled modulator destination: %d\n", mod->mDstOp);
+ else if(src0in != AL_INVALID && src0form != AL_INVALID && src0type != AL_INVALID &&
+ src1in != AL_INVALID && src1form != AL_INVALID && src0type != AL_INVALID &&
+ trans != AL_INVALID)
{
- ALenum src0in = getModSrcInput(zone->mods[i].mSrcOp&0xFF);
- ALenum src0type = getModSrcType(zone->mods[i].mSrcOp&0x0300);
- ALenum src0form = getModSrcForm(zone->mods[i].mSrcOp&0xFC00);
- ALenum src1in = getModSrcInput(zone->mods[i].mAmtSrcOp&0xFF);
- ALenum src1type = getModSrcType(zone->mods[i].mAmtSrcOp&0x0300);
- ALenum src1form = getModSrcForm(zone->mods[i].mAmtSrcOp&0xFC00);
- ALenum trans = getModTransOp(zone->mods[i].mTransOp);
- ALenum dst = (zone->mods[i].mDstOp < 60) ? Gen2Param[zone->mods[i].mDstOp] : 0;
- if(!dst || dst == AL_KEY_RANGE_SOFT || dst == AL_VELOCITY_RANGE_SOFT ||
- dst == AL_LOOP_MODE_SOFT || dst == AL_EXCLUSIVE_CLASS_SOFT ||
- dst == AL_BASE_KEY_SOFT)
- ERR("Unhandled modulator destination: %d\n", zone->mods[i].mDstOp);
- else if(src0in != AL_INVALID && src0form != AL_INVALID && src0type != AL_INVALID &&
- src1in != AL_INVALID && src1form != AL_INVALID && src0type != AL_INVALID &&
- trans != AL_INVALID)
- {
- ALfontsound_setModStagei(sound, context, i, AL_SOURCE0_INPUT_SOFT, src0in);
- ALfontsound_setModStagei(sound, context, i, AL_SOURCE0_TYPE_SOFT, src0type);
- ALfontsound_setModStagei(sound, context, i, AL_SOURCE0_FORM_SOFT, src0form);
- ALfontsound_setModStagei(sound, context, i, AL_SOURCE1_INPUT_SOFT, src1in);
- ALfontsound_setModStagei(sound, context, i, AL_SOURCE1_TYPE_SOFT, src1type);
- ALfontsound_setModStagei(sound, context, i, AL_SOURCE1_FORM_SOFT, src1form);
- ALfontsound_setModStagei(sound, context, i, AL_AMOUNT_SOFT, zone->mods[i].mAmount);
- ALfontsound_setModStagei(sound, context, i, AL_TRANSFORM_OP_SOFT, trans);
- ALfontsound_setModStagei(sound, context, i, AL_DESTINATION_SOFT, dst);
- }
+ ALsizei idx = (ALsizei)(mod - VECTOR_ITER_BEGIN(zone->mods));
+ ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_INPUT_SOFT, src0in);
+ ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_TYPE_SOFT, src0type);
+ ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_FORM_SOFT, src0form);
+ ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_INPUT_SOFT, src1in);
+ ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_TYPE_SOFT, src1type);
+ ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_FORM_SOFT, src1form);
+ ALfontsound_setModStagei(sound, context, idx, AL_AMOUNT_SOFT, mod->mAmount);
+ ALfontsound_setModStagei(sound, context, idx, AL_TRANSFORM_OP_SOFT, trans);
+ ALfontsound_setModStagei(sound, context, idx, AL_DESTINATION_SOFT, dst);
}
}
- gen = zone->gens;
- gen_end = gen + zone->gens_size;
+ gen = VECTOR_ITER_BEGIN(zone->gens);
+ gen_end = VECTOR_ITER_END(zone->gens);
for(;gen != gen_end;gen++)
{
ALint value = (ALshort)gen->mAmount;
@@ -1019,8 +942,8 @@ static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCco
temp = realloc(*sounds, (zone_end-zone + *sounds_size)*sizeof((*sounds)[0]));
if(!temp)
{
- ERR("Failed reallocating fontsound storage to %ld elements (from %d)\n",
- (zone_end-zone + *sounds_size), *sounds_size);
+ ERR("Failed reallocating fontsound storage to %d elements (from %d)\n",
+ (ALsizei)(zone_end-zone) + *sounds_size, *sounds_size);
return;
}
*sounds = temp;
@@ -1049,13 +972,13 @@ static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCco
}
samp = &sfont->shdr[gen->mAmount];
- gen = pzone->gens;
- gen_end = gen + pzone->gens_size;
+ gen = VECTOR_ITER_BEGIN(pzone->gens);
+ gen_end = VECTOR_ITER_END(pzone->gens);
for(;gen != gen_end;gen++)
GenModList_accumGen(&lzone, gen);
- mod = pzone->mods;
- mod_end = mod + pzone->mods_size;
+ mod = VECTOR_ITER_BEGIN(pzone->mods);
+ mod_end = VECTOR_ITER_END(pzone->mods);
for(;mod != mod_end;mod++)
GenModList_accumMod(&lzone, mod);
@@ -1156,6 +1079,8 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
TRACE("SF2 ROM ID: %s\n", sfont.irom);
}
}
+ else
+ TRACE("Skipping INFO sub-chunk '%c%c%c%c' (%u bytes)\n", FOURCCARGS(info.mCode), info.mSize);
list.mSize -= info.mSize;
skip(stream, info.mSize);
}
diff --git a/Alc/midi/soft.c b/Alc/midi/soft.c
new file mode 100644
index 00000000..7102ff7a
--- /dev/null
+++ b/Alc/midi/soft.c
@@ -0,0 +1,141 @@
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "alMain.h"
+#include "alError.h"
+#include "evtqueue.h"
+#include "alu.h"
+
+#include "midi/base.h"
+
+
+typedef struct SSynth {
+ DERIVE_FROM_TYPE(MidiSynth);
+} SSynth;
+
+static void SSynth_mixSamples(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
+
+static void SSynth_Construct(SSynth *self, ALCdevice *device);
+static void SSynth_Destruct(SSynth *self);
+static DECLARE_FORWARD3(SSynth, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*)
+static DECLARE_FORWARD1(SSynth, MidiSynth, void, setGain, ALfloat)
+static DECLARE_FORWARD(SSynth, MidiSynth, void, stop)
+static DECLARE_FORWARD(SSynth, MidiSynth, void, reset)
+static void SSynth_update(SSynth *self, ALCdevice *device);
+static void SSynth_process(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
+DECLARE_DEFAULT_ALLOCATORS(SSynth)
+DEFINE_MIDISYNTH_VTABLE(SSynth);
+
+
+static void SSynth_Construct(SSynth *self, ALCdevice *device)
+{
+ MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device);
+ SET_VTABLE2(SSynth, MidiSynth, self);
+}
+
+static void SSynth_Destruct(SSynth* UNUSED(self))
+{
+}
+
+
+static void SSynth_update(SSynth* UNUSED(self), ALCdevice* UNUSED(device))
+{
+}
+
+
+static void SSynth_mixSamples(SSynth* UNUSED(self), ALuint UNUSED(SamplesToDo), ALfloat (*restrict DryBuffer)[BUFFERSIZE])
+{
+ (void)DryBuffer;
+}
+
+
+static void SSynth_processQueue(SSynth *self, ALuint64 time)
+{
+ EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue;
+
+ while(queue->pos < queue->size && queue->events[queue->pos].time <= time)
+ queue->pos++;
+}
+
+static void SSynth_process(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE])
+{
+ MidiSynth *synth = STATIC_CAST(MidiSynth, self);
+ ALenum state = synth->State;
+ ALuint64 curtime;
+ ALuint total = 0;
+
+ if(state == AL_INITIAL)
+ return;
+ if(state != AL_PLAYING)
+ {
+ SSynth_mixSamples(self, SamplesToDo, DryBuffer);
+ return;
+ }
+
+ curtime = MidiSynth_getTime(synth);
+ while(total < SamplesToDo)
+ {
+ ALuint64 time, diff;
+ ALint tonext;
+
+ time = MidiSynth_getNextEvtTime(synth);
+ diff = maxu64(time, curtime) - curtime;
+ if(diff >= MIDI_CLOCK_RES || time == UINT64_MAX)
+ {
+ /* If there's no pending event, or if it's more than 1 second
+ * away, do as many samples as we can. */
+ tonext = INT_MAX;
+ }
+ else
+ {
+ /* Figure out how many samples until the next event. */
+ tonext = (ALint)((diff*synth->SampleRate + (MIDI_CLOCK_RES-1)) / MIDI_CLOCK_RES);
+ tonext -= total;
+ /* For efficiency reasons, try to mix a multiple of 64 samples
+ * (~1ms @ 44.1khz) before processing the next event. */
+ tonext = (tonext+63) & ~63;
+ }
+
+ if(tonext > 0)
+ {
+ ALuint todo = mini(tonext, SamplesToDo-total);
+ SSynth_mixSamples(self, todo, DryBuffer);
+ total += todo;
+ tonext -= todo;
+ }
+ if(total < SamplesToDo && tonext <= 0)
+ SSynth_processQueue(self, time);
+ }
+
+ synth->SamplesDone += SamplesToDo;
+ synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES;
+ synth->SamplesDone %= synth->SampleRate;
+}
+
+
+MidiSynth *SSynth_create(ALCdevice *device)
+{
+ SSynth *synth;
+
+ /* This option is temporary. Once this synth is in a more usable state, a
+ * more generic selector should be used. */
+ if(!GetConfigValueBool("midi", "internal-synth", 0))
+ {
+ TRACE("Not using internal MIDI synth\n");
+ return NULL;
+ }
+
+ synth = SSynth_New(sizeof(*synth));
+ if(!synth)
+ {
+ ERR("Failed to allocate SSynth\n");
+ return NULL;
+ }
+ SSynth_Construct(synth, device);
+ return STATIC_CAST(MidiSynth, synth);
+}
diff --git a/Alc/mixer.c b/Alc/mixer.c
index acd6c610..6a4abfc6 100644
--- a/Alc/mixer.c
+++ b/Alc/mixer.c
@@ -37,6 +37,9 @@
#include "bs2b.h"
+extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size);
+
+
static inline ALfloat Sample_ALbyte(ALbyte val)
{ return val * (1.0f/127.0f); }
@@ -84,21 +87,44 @@ static void SilenceData(ALfloat *dst, ALuint samples)
}
-static void DoFilter(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src,
- ALuint numsamples)
+static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
+ ALfloat *restrict dst, const ALfloat *restrict src,
+ ALuint numsamples, enum ActiveFilters type)
{
ALuint i;
- for(i = 0;i < numsamples;i++)
- dst[i] = ALfilterState_processSingle(filter, src[i]);
- dst[i] = ALfilterState_processSingleC(filter, src[i]);
+ switch(type)
+ {
+ case AF_None:
+ break;
+
+ case AF_LowPass:
+ ALfilterState_process(lpfilter, dst, src, numsamples);
+ return dst;
+ case AF_HighPass:
+ ALfilterState_process(hpfilter, dst, src, numsamples);
+ return dst;
+
+ case AF_BandPass:
+ for(i = 0;i < numsamples;)
+ {
+ ALfloat temp[64];
+ ALuint todo = minu(64, numsamples-i);
+
+ ALfilterState_process(lpfilter, temp, src+i, todo);
+ ALfilterState_process(hpfilter, dst+i, temp, todo);
+ i += todo;
+ }
+ return dst;
+ }
+ return src;
}
-ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
+ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
{
+ ALsource *Source = src->Source;
ALbufferlistitem *BufferListItem;
ALuint DataPosInt, DataPosFrac;
- ALuint BuffersPlayed;
ALboolean Looping;
ALuint increment;
enum Resampler Resampler;
@@ -110,20 +136,17 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
ALuint chan, j;
/* Get source info */
- State = Source->state;
- BuffersPlayed = Source->BuffersPlayed;
- DataPosInt = Source->position;
- DataPosFrac = Source->position_fraction;
- Looping = Source->Looping;
- increment = Source->Params.Step;
- Resampler = (increment==FRACTIONONE) ? PointResampler : Source->Resampler;
- NumChannels = Source->NumChannels;
- SampleSize = Source->SampleSize;
+ State = Source->state;
+ BufferListItem = Source->current_buffer;
+ DataPosInt = Source->position;
+ DataPosFrac = Source->position_fraction;
+ Looping = Source->Looping;
+ increment = src->Step;
+ Resampler = (increment==FRACTIONONE) ? PointResampler : Source->Resampler;
+ NumChannels = Source->NumChannels;
+ SampleSize = Source->SampleSize;
/* Get current buffer queue item */
- BufferListItem = Source->queue;
- for(j = 0;j < BuffersPlayed;j++)
- BufferListItem = BufferListItem->next;
OutPos = 0;
do {
@@ -132,7 +155,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
ALuint SrcBufferSize, DstBufferSize;
/* Figure out how many buffer samples will be needed */
- DataSize64 = SamplesToDo-OutPos+1;
+ DataSize64 = SamplesToDo-OutPos;
DataSize64 *= increment;
DataSize64 += DataPosFrac+FRACTIONMASK;
DataSize64 >>= FRACTIONBITS;
@@ -144,7 +167,6 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
DataSize64 = SrcBufferSize;
DataSize64 -= BufferPadding+BufferPrePadding;
DataSize64 <<= FRACTIONBITS;
- DataSize64 -= increment;
DataSize64 -= DataPosFrac;
DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
@@ -157,13 +179,13 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
for(chan = 0;chan < NumChannels;chan++)
{
- ALfloat *SrcData = Device->SampleData1;
- ALfloat *ResampledData = Device->SampleData2;
+ const ALfloat *ResampledData;
+ ALfloat *SrcData = Device->SourceData;
ALuint SrcDataSize = 0;
if(Source->SourceType == AL_STATIC)
{
- const ALbuffer *ALBuffer = Source->queue->buffer;
+ const ALbuffer *ALBuffer = BufferListItem->buffer;
const ALubyte *Data = ALBuffer->data;
ALuint DataSize;
ALuint pos;
@@ -256,7 +278,15 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
pos = BufferPrePadding - DataPosInt;
while(pos > 0)
{
- if(!tmpiter->prev && !Looping)
+ ALbufferlistitem *prev;
+ if((prev=tmpiter->prev) != NULL)
+ tmpiter = prev;
+ else if(Looping)
+ {
+ while(tmpiter->next)
+ tmpiter = tmpiter->next;
+ }
+ else
{
ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos);
@@ -267,14 +297,6 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
break;
}
- if(tmpiter->prev)
- tmpiter = tmpiter->prev;
- else
- {
- while(tmpiter->next)
- tmpiter = tmpiter->next;
- }
-
if(tmpiter->buffer)
{
if((ALuint)tmpiter->buffer->SampleLen > pos)
@@ -322,38 +344,57 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
}
/* Now resample, then filter and mix to the appropriate outputs. */
- Source->Params.Resample(&SrcData[BufferPrePadding], DataPosFrac,
- increment, ResampledData, DstBufferSize);
-
+ ResampledData = src->Resample(
+ &SrcData[BufferPrePadding], DataPosFrac, increment,
+ Device->ResampledData, DstBufferSize
+ );
{
- DirectParams *directparms = &Source->Params.Direct;
-
- DoFilter(&directparms->LpFilter[chan], SrcData, ResampledData,
- DstBufferSize);
- Source->Params.DryMix(directparms, SrcData, chan, OutPos,
- SamplesToDo, DstBufferSize);
+ DirectParams *parms = &src->Direct;
+ const ALfloat *samples;
+
+ samples = DoFilters(
+ &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
+ Device->FilteredData, ResampledData, DstBufferSize,
+ parms->Filters[chan].ActiveType
+ );
+ if(!src->IsHrtf)
+ src->Dry.Mix(parms->OutBuffer, samples, &parms->Mix.Gains[chan],
+ parms->Counter, OutPos, DstBufferSize);
+ else
+ src->Dry.HrtfMix(
+ parms->OutBuffer, samples, parms->Counter, src->Offset,
+ OutPos, parms->Mix.Hrtf.IrSize, &parms->Mix.Hrtf.Params[chan],
+ &parms->Mix.Hrtf.State[chan], DstBufferSize
+ );
}
for(j = 0;j < Device->NumAuxSends;j++)
{
- SendParams *sendparms = &Source->Params.Send[j];
- if(!sendparms->OutBuffer)
+ SendParams *parms = &src->Send[j];
+ const ALfloat *samples;
+
+ if(!parms->OutBuffer)
continue;
- DoFilter(&sendparms->LpFilter[chan], SrcData, ResampledData,
- DstBufferSize);
- Source->Params.WetMix(sendparms, SrcData, OutPos,
- SamplesToDo, DstBufferSize);
+ samples = DoFilters(
+ &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
+ Device->FilteredData, ResampledData, DstBufferSize,
+ parms->Filters[chan].ActiveType
+ );
+ src->WetMix(parms->OutBuffer, samples, &parms->Gain,
+ parms->Counter, OutPos, DstBufferSize);
}
}
/* Update positions */
- for(j = 0;j < DstBufferSize;j++)
- {
- DataPosFrac += increment;
- DataPosInt += DataPosFrac>>FRACTIONBITS;
- DataPosFrac &= FRACTIONMASK;
- }
+ DataPosFrac += increment*DstBufferSize;
+ DataPosInt += DataPosFrac>>FRACTIONBITS;
+ DataPosFrac &= FRACTIONMASK;
+
OutPos += DstBufferSize;
+ src->Offset += DstBufferSize;
+ src->Direct.Counter = maxu(src->Direct.Counter, DstBufferSize) - DstBufferSize;
+ for(j = 0;j < Device->NumAuxSends;j++)
+ src->Send[j].Counter = maxu(src->Send[j].Counter, DstBufferSize) - DstBufferSize;
/* Handle looping sources */
while(1)
@@ -374,6 +415,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
if(Looping && Source->SourceType == AL_STATIC)
{
+ assert(LoopEnd > LoopStart);
DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
break;
}
@@ -382,20 +424,13 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
break;
if(BufferListItem->next)
- {
BufferListItem = BufferListItem->next;
- BuffersPlayed++;
- }
else if(Looping)
- {
BufferListItem = Source->queue;
- BuffersPlayed = 0;
- }
else
{
State = AL_STOPPED;
- BufferListItem = Source->queue;
- BuffersPlayed = Source->BuffersInQueue;
+ BufferListItem = NULL;
DataPosInt = 0;
DataPosFrac = 0;
break;
@@ -407,15 +442,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
/* Update source info */
Source->state = State;
- Source->BuffersPlayed = BuffersPlayed;
+ Source->current_buffer = BufferListItem;
Source->position = DataPosInt;
Source->position_fraction = DataPosFrac;
- Source->Hrtf.Offset += OutPos;
- if(State == AL_PLAYING)
- Source->Hrtf.Counter = maxu(Source->Hrtf.Counter, OutPos) - OutPos;
- else
- {
- Source->Hrtf.Counter = 0;
- Source->Hrtf.Moving = AL_FALSE;
- }
}
diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c
index 36d8bf5a..6dd01e7d 100644
--- a/Alc/mixer_c.c
+++ b/Alc/mixer_c.c
@@ -15,28 +15,33 @@ static inline ALfloat lerp32(const ALfloat *vals, ALuint frac)
static inline ALfloat cubic32(const ALfloat *vals, ALuint frac)
{ return cubic(vals[-1], vals[0], vals[1], vals[2], frac * (1.0f/FRACTIONONE)); }
-void Resample_copy32_C(const ALfloat *data, ALuint UNUSED(frac),
- ALuint increment, ALfloat *restrict OutBuffer, ALuint BufferSize)
+const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac),
+ ALuint increment, ALfloat *restrict dst, ALuint numsamples)
{
assert(increment==FRACTIONONE);
- memcpy(OutBuffer, data, (BufferSize+1)*sizeof(ALfloat));
+#if defined(HAVE_SSE) || defined(HAVE_NEON)
+ /* Avoid copying the source data if it's aligned like the destination. */
+ if((((intptr_t)src)&15) == (((intptr_t)dst)&15))
+ return src;
+#endif
+ memcpy(dst, src, numsamples*sizeof(ALfloat));
+ return dst;
}
#define DECL_TEMPLATE(Sampler) \
-void Resample_##Sampler##_C(const ALfloat *data, ALuint frac, \
- ALuint increment, ALfloat *restrict OutBuffer, ALuint BufferSize) \
+const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \
+ ALuint increment, ALfloat *restrict dst, ALuint numsamples) \
{ \
- ALuint pos = 0; \
ALuint i; \
- \
- for(i = 0;i < BufferSize+1;i++) \
+ for(i = 0;i < numsamples;i++) \
{ \
- OutBuffer[i] = Sampler(data + pos, frac); \
+ dst[i] = Sampler(src, frac); \
\
frac += increment; \
- pos += frac>>FRACTIONBITS; \
+ src += frac>>FRACTIONBITS; \
frac &= FRACTIONMASK; \
} \
+ return dst; \
}
DECL_TEMPLATE(point32)
@@ -46,13 +51,26 @@ DECL_TEMPLATE(cubic32)
#undef DECL_TEMPLATE
-static inline void ApplyCoeffsStep(const ALuint IrSize,
+void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples)
+{
+ ALuint i;
+ for(i = 0;i < numsamples;i++)
+ *(dst++) = ALfilterState_processSingle(filter, *(src++));
+}
+
+
+static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
+ const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
- const ALfloat (*restrict CoeffStep)[2])
+ const ALfloat (*restrict CoeffStep)[2],
+ ALfloat left, ALfloat right)
{
ALuint c;
for(c = 0;c < IrSize;c++)
{
+ const ALuint off = (Offset+c)&HRIR_MASK;
+ Values[off][0] += Coeffs[c][0] * left;
+ Values[off][1] += Coeffs[c][1] * right;
Coeffs[c][0] += CoeffStep[c][0];
Coeffs[c][1] += CoeffStep[c][1];
}
@@ -77,49 +95,61 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
#undef SUFFIX
-void MixDirect_C(const DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
- ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
+void MixDirect_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
- ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
- ALfloat *restrict ClickRemoval = params->ClickRemoval;
- ALfloat *restrict PendingClicks = params->PendingClicks;
- ALfloat DrySend;
- ALuint pos;
+ ALfloat DrySend, Step;
ALuint c;
for(c = 0;c < MaxChannels;c++)
{
- DrySend = params->Gains[srcchan][c];
+ ALuint pos = 0;
+ DrySend = Gains->Current[c];
+ Step = Gains->Step[c];
+ if(Step != 1.0f && Counter > 0)
+ {
+ for(;pos < BufferSize && pos < Counter;pos++)
+ {
+ OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
+ DrySend *= Step;
+ }
+ if(pos == Counter)
+ DrySend = Gains->Target[c];
+ Gains->Current[c] = DrySend;
+ }
+
if(!(DrySend > GAIN_SILENCE_THRESHOLD))
continue;
-
- if(OutPos == 0)
- ClickRemoval[c] -= data[0]*DrySend;
- for(pos = 0;pos < BufferSize;pos++)
+ for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
- if(OutPos+pos == SamplesToDo)
- PendingClicks[c] += data[pos]*DrySend;
}
}
-void MixSend_C(const SendParams *params, const ALfloat *restrict data,
- ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
+void MixSend_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ MixGainMono *Gain, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
- ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
- ALfloat *restrict ClickRemoval = params->ClickRemoval;
- ALfloat *restrict PendingClicks = params->PendingClicks;
- ALfloat WetSend;
- ALuint pos;
-
- WetSend = params->Gain;
- if(!(WetSend > GAIN_SILENCE_THRESHOLD))
- return;
-
- if(OutPos == 0)
- ClickRemoval[0] -= data[0] * WetSend;
- for(pos = 0;pos < BufferSize;pos++)
- OutBuffer[0][OutPos+pos] += data[pos] * WetSend;
- if(OutPos+pos == SamplesToDo)
- PendingClicks[0] += data[pos] * WetSend;
+ ALfloat WetSend, Step;
+
+ {
+ ALuint pos = 0;
+ WetSend = Gain->Current;
+ Step = Gain->Step;
+ if(Step != 1.0f && Counter > 0)
+ {
+ for(;pos < BufferSize && pos < Counter;pos++)
+ {
+ OutBuffer[0][OutPos+pos] += data[pos]*WetSend;
+ WetSend *= Step;
+ }
+ if(pos == Counter)
+ WetSend = Gain->Target;
+ Gain->Current = WetSend;
+ }
+
+ if(!(WetSend > GAIN_SILENCE_THRESHOLD))
+ return;
+ for(;pos < BufferSize;pos++)
+ OutBuffer[0][OutPos+pos] += data[pos] * WetSend;
+ }
}
diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h
index f8968a0a..caa06c25 100644
--- a/Alc/mixer_defs.h
+++ b/Alc/mixer_defs.h
@@ -4,30 +4,75 @@
#include "AL/alc.h"
#include "AL/al.h"
#include "alMain.h"
+#include "alu.h"
-struct DirectParams;
-struct SendParams;
+struct MixGains;
+struct MixGainMono;
+
+struct HrtfParams;
+struct HrtfState;
/* C resamplers */
-void Resample_copy32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-void Resample_point32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-void Resample_lerp32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-void Resample_cubic32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_point32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_lerp32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_cubic32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
/* C mixers */
-void MixDirect_Hrtf_C(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
-void MixDirect_C(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
-void MixSend_C(const struct SendParams*,const ALfloat*restrict,ALuint,ALuint,ALuint);
+void MixDirect_Hrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
+ const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
+ ALuint BufferSize);
+void MixDirect_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ struct MixGains *Gains, ALuint Counter, ALuint OutPos,
+ ALuint BufferSize);
+void MixSend_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ struct MixGainMono *Gain, ALuint Counter, ALuint OutPos,
+ ALuint BufferSize);
/* SSE mixers */
-void MixDirect_Hrtf_SSE(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
-void MixDirect_SSE(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
-void MixSend_SSE(const struct SendParams*,const ALfloat*restrict,ALuint,ALuint,ALuint);
+void MixDirect_Hrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
+ const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
+ ALuint BufferSize);
+void MixDirect_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ struct MixGains *Gains, ALuint Counter, ALuint OutPos,
+ ALuint BufferSize);
+void MixSend_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ struct MixGainMono *Gain, ALuint Counter, ALuint OutPos,
+ ALuint BufferSize);
+
+/* SSE resamplers */
+inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size)
+{
+ ALuint i;
+
+ pos_arr[0] = 0;
+ frac_arr[0] = frac;
+ for(i = 1;i < size;i++)
+ {
+ ALuint frac_tmp = frac_arr[i-1] + increment;
+ pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS);
+ frac_arr[i] = frac_tmp&FRACTIONMASK;
+ }
+}
+
+const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples);
+const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples);
/* Neon mixers */
-void MixDirect_Hrtf_Neon(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
-void MixDirect_Neon(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
-void MixSend_Neon(const struct SendParams*,const ALfloat*restrict,ALuint,ALuint,ALuint);
+void MixDirect_Hrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
+ const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
+ ALuint BufferSize);
+void MixDirect_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ struct MixGains *Gains, ALuint Counter, ALuint OutPos,
+ ALuint BufferSize);
+void MixSend_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ struct MixGainMono *Gain, ALuint Counter, ALuint OutPos,
+ ALuint BufferSize);
#endif /* MIXER_DEFS_H */
diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c
index 17be5cde..7c90ae9c 100644
--- a/Alc/mixer_inc.c
+++ b/Alc/mixer_inc.c
@@ -2,15 +2,11 @@
#include "alMain.h"
#include "alSource.h"
+
+#include "hrtf.h"
#include "mixer_defs.h"
+#include "align.h"
-#ifdef __GNUC__
-#define LIKELY(x) __builtin_expect(!!(x), 1)
-#define UNLIKELY(x) __builtin_expect(!!(x), 0)
-#else
-#define LIKELY(x) (x)
-#define UNLIKELY(x) (x)
-#endif
#define REAL_MERGE2(a,b) a##b
#define MERGE2(a,b) REAL_MERGE2(a,b)
@@ -18,116 +14,76 @@
#define MixDirect_Hrtf MERGE2(MixDirect_Hrtf_,SUFFIX)
-static inline void ApplyCoeffsStep(const ALuint irSize,
+static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
+ const ALuint irSize,
ALfloat (*restrict Coeffs)[2],
- const ALfloat (*restrict CoeffStep)[2]);
+ const ALfloat (*restrict CoeffStep)[2],
+ ALfloat left, ALfloat right);
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint irSize,
ALfloat (*restrict Coeffs)[2],
ALfloat left, ALfloat right);
-void MixDirect_Hrtf(const DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
- ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
+void MixDirect_Hrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
+ const HrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize)
{
- ALfloat (*restrict DryBuffer)[BUFFERSIZE] = params->OutBuffer;
- ALfloat *restrict ClickRemoval = params->ClickRemoval;
- ALfloat *restrict PendingClicks = params->PendingClicks;
- const ALuint IrSize = params->Hrtf.Params.IrSize;
- const ALint *restrict DelayStep = params->Hrtf.Params.DelayStep;
- const ALfloat (*restrict CoeffStep)[2] = params->Hrtf.Params.CoeffStep;
- const ALfloat (*restrict TargetCoeffs)[2] = params->Hrtf.Params.Coeffs[srcchan];
- const ALuint *restrict TargetDelay = params->Hrtf.Params.Delay[srcchan];
- ALfloat *restrict History = params->Hrtf.State->History[srcchan];
- ALfloat (*restrict Values)[2] = params->Hrtf.State->Values[srcchan];
- ALint Counter = maxu(params->Hrtf.State->Counter, OutPos) - OutPos;
- ALuint Offset = params->Hrtf.State->Offset + OutPos;
- ALIGN(16) ALfloat Coeffs[HRIR_LENGTH][2];
+ alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
ALuint Delay[2];
ALfloat left, right;
ALuint pos;
ALuint c;
- pos = 0;
for(c = 0;c < IrSize;c++)
{
- Coeffs[c][0] = TargetCoeffs[c][0] - (CoeffStep[c][0]*Counter);
- Coeffs[c][1] = TargetCoeffs[c][1] - (CoeffStep[c][1]*Counter);
+ Coeffs[c][0] = hrtfparams->Coeffs[c][0] - (hrtfparams->CoeffStep[c][0]*Counter);
+ Coeffs[c][1] = hrtfparams->Coeffs[c][1] - (hrtfparams->CoeffStep[c][1]*Counter);
}
+ Delay[0] = hrtfparams->Delay[0] - (hrtfparams->DelayStep[0]*Counter);
+ Delay[1] = hrtfparams->Delay[1] - (hrtfparams->DelayStep[1]*Counter);
- Delay[0] = TargetDelay[0] - (DelayStep[0]*Counter);
- Delay[1] = TargetDelay[1] - (DelayStep[1]*Counter);
-
- if(LIKELY(OutPos == 0))
+ for(pos = 0;pos < BufferSize && pos < Counter;pos++)
{
- History[Offset&SRC_HISTORY_MASK] = data[pos];
- left = lerp(History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
- History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
+ hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos];
+ left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
+ hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
(Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
- right = lerp(History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
- History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
+ right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
+ hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
(Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
- ClickRemoval[FrontLeft] -= Values[(Offset+1)&HRIR_MASK][0] +
- Coeffs[0][0] * left;
- ClickRemoval[FrontRight] -= Values[(Offset+1)&HRIR_MASK][1] +
- Coeffs[0][1] * right;
- }
- for(pos = 0;pos < BufferSize && Counter > 0;pos++)
- {
- History[Offset&SRC_HISTORY_MASK] = data[pos];
- left = lerp(History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
- History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
- (Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
- right = lerp(History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
- History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
- (Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
+ Delay[0] += hrtfparams->DelayStep[0];
+ Delay[1] += hrtfparams->DelayStep[1];
- Delay[0] += DelayStep[0];
- Delay[1] += DelayStep[1];
-
- Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
- Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
+ hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
+ hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
Offset++;
- ApplyCoeffs(Offset, Values, IrSize, Coeffs, left, right);
- DryBuffer[FrontLeft][OutPos] += Values[Offset&HRIR_MASK][0];
- DryBuffer[FrontRight][OutPos] += Values[Offset&HRIR_MASK][1];
- ApplyCoeffsStep(IrSize, Coeffs, CoeffStep);
-
+ ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->CoeffStep, left, right);
+ OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
+ OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
OutPos++;
- Counter--;
}
Delay[0] >>= HRTFDELAY_BITS;
Delay[1] >>= HRTFDELAY_BITS;
for(;pos < BufferSize;pos++)
{
- History[Offset&SRC_HISTORY_MASK] = data[pos];
- left = History[(Offset-Delay[0])&SRC_HISTORY_MASK];
- right = History[(Offset-Delay[1])&SRC_HISTORY_MASK];
+ hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos];
+ left = hrtfstate->History[(Offset-Delay[0])&SRC_HISTORY_MASK];
+ right = hrtfstate->History[(Offset-Delay[1])&SRC_HISTORY_MASK];
- Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
- Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
+ hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
+ hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
Offset++;
- ApplyCoeffs(Offset, Values, IrSize, Coeffs, left, right);
- DryBuffer[FrontLeft][OutPos] += Values[Offset&HRIR_MASK][0];
- DryBuffer[FrontRight][OutPos] += Values[Offset&HRIR_MASK][1];
+ ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right);
+ OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
+ OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
OutPos++;
}
- if(LIKELY(OutPos == SamplesToDo))
- {
- History[Offset&SRC_HISTORY_MASK] = data[pos];
- left = History[(Offset-Delay[0])&SRC_HISTORY_MASK];
- right = History[(Offset-Delay[1])&SRC_HISTORY_MASK];
-
- PendingClicks[FrontLeft] += Values[(Offset+1)&HRIR_MASK][0] +
- Coeffs[0][0] * left;
- PendingClicks[FrontRight] += Values[(Offset+1)&HRIR_MASK][1] +
- Coeffs[0][1] * right;
- }
}
@@ -135,6 +91,3 @@ void MixDirect_Hrtf(const DirectParams *params, const ALfloat *restrict data, AL
#undef MERGE2
#undef REAL_MERGE2
-
-#undef UNLIKELY
-#undef LIKELY
diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c
index 0aa450ad..6a0421a5 100644
--- a/Alc/mixer_neon.c
+++ b/Alc/mixer_neon.c
@@ -1,28 +1,43 @@
#include "config.h"
-#ifdef HAVE_ARM_NEON_H
#include <arm_neon.h>
-#endif
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alu.h"
+#include "hrtf.h"
-static inline void ApplyCoeffsStep(const ALuint IrSize,
+static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
+ const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
- const ALfloat (*restrict CoeffStep)[2])
+ const ALfloat (*restrict CoeffStep)[2],
+ ALfloat left, ALfloat right)
{
- float32x4_t coeffs, deltas;
ALuint c;
-
+ float32x4_t leftright4;
+ {
+ float32x2_t leftright2 = vdup_n_f32(0.0);
+ leftright2 = vset_lane_f32(left, leftright2, 0);
+ leftright2 = vset_lane_f32(right, leftright2, 1);
+ leftright4 = vcombine_f32(leftright2, leftright2);
+ }
for(c = 0;c < IrSize;c += 2)
{
- coeffs = vld1q_f32(&Coeffs[c][0]);
- deltas = vld1q_f32(&CoeffStep[c][0]);
- coeffs = vaddq_f32(coeffs, deltas);
- vst1q_f32(&Coeffs[c][0], coeffs);
+ const ALuint o0 = (Offset+c)&HRIR_MASK;
+ const ALuint o1 = (o0+1)&HRIR_MASK;
+ float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]),
+ vld1_f32((float32_t*)&Values[o1][0]));
+ float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]);
+ float32x4_t deltas = vld1q_f32(&CoeffStep[c][0]);
+
+ vals = vmlaq_f32(vals, coefs, leftright4);
+ coefs = vaddq_f32(coefs, deltas);
+
+ vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals));
+ vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals));
+ vst1q_f32(&Coeffs[c][0], coefs);
}
}
@@ -60,28 +75,37 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
#undef SUFFIX
-void MixDirect_Neon(const DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
- ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
+void MixDirect_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
- ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
- ALfloat *restrict ClickRemoval = params->ClickRemoval;
- ALfloat *restrict PendingClicks = params->PendingClicks;
- ALfloat DrySend;
+ ALfloat DrySend, Step;
float32x4_t gain;
- ALuint pos;
ALuint c;
for(c = 0;c < MaxChannels;c++)
{
- DrySend = params->Gains[srcchan][c];
+ ALuint pos = 0;
+ DrySend = Gains->Current[c];
+ Step = Gains->Step[c];
+ if(Step != 1.0f && Counter > 0)
+ {
+ for(;pos < BufferSize && pos < Counter;pos++)
+ {
+ OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
+ DrySend *= Step;
+ }
+ if(pos == Counter)
+ DrySend = Gains->Target[c];
+ Gains->Current[c] = DrySend;
+ /* Mix until pos is aligned with 4 or the mix is done. */
+ for(;pos < BufferSize && (pos&3) != 0;pos++)
+ OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
+ }
+
if(!(DrySend > GAIN_SILENCE_THRESHOLD))
continue;
-
- if(OutPos == 0)
- ClickRemoval[c] -= data[0]*DrySend;
-
gain = vdupq_n_f32(DrySend);
- for(pos = 0;BufferSize-pos > 3;pos += 4)
+ for(;BufferSize-pos > 3;pos += 4)
{
const float32x4_t val4 = vld1q_f32(&data[pos]);
float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]);
@@ -90,41 +114,45 @@ void MixDirect_Neon(const DirectParams *params, const ALfloat *restrict data, AL
}
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
-
- if(OutPos+pos == SamplesToDo)
- PendingClicks[c] += data[pos]*DrySend;
}
}
-void MixSend_Neon(const SendParams *params, const ALfloat *restrict data,
- ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
+void MixSend_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ MixGainMono *Gain, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
- ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
- ALfloat *restrict ClickRemoval = params->ClickRemoval;
- ALfloat *restrict PendingClicks = params->PendingClicks;
- ALfloat WetGain;
+ ALfloat WetGain, Step;
float32x4_t gain;
- ALuint pos;
-
- WetGain = params->Gain;
- if(!(WetGain > GAIN_SILENCE_THRESHOLD))
- return;
-
- if(OutPos == 0)
- ClickRemoval[0] -= data[0] * WetGain;
- gain = vdupq_n_f32(WetGain);
- for(pos = 0;BufferSize-pos > 3;pos += 4)
{
- const float32x4_t val4 = vld1q_f32(&data[pos]);
- float32x4_t wet4 = vld1q_f32(&OutBuffer[0][OutPos+pos]);
- wet4 = vaddq_f32(wet4, vmulq_f32(val4, gain));
- vst1q_f32(&OutBuffer[0][OutPos+pos], wet4);
- }
- for(;pos < BufferSize;pos++)
- OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
+ ALuint pos = 0;
+ WetGain = Gain->Current;
+ Step = Gain->Step;
+ if(Step != 1.0f && Counter > 0)
+ {
+ for(;pos < BufferSize && pos < Counter;pos++)
+ {
+ OutBuffer[0][OutPos+pos] += data[pos]*WetGain;
+ WetGain *= Step;
+ }
+ if(pos == Counter)
+ WetGain = Gain->Target;
+ Gain->Current = WetGain;
+ for(;pos < BufferSize && (pos&3) != 0;pos++)
+ OutBuffer[0][OutPos+pos] += data[pos]*WetGain;
+ }
- if(OutPos+pos == SamplesToDo)
- PendingClicks[0] += data[pos] * WetGain;
+ if(!(WetGain > GAIN_SILENCE_THRESHOLD))
+ return;
+ gain = vdupq_n_f32(WetGain);
+ for(;BufferSize-pos > 3;pos += 4)
+ {
+ const float32x4_t val4 = vld1q_f32(&data[pos]);
+ float32x4_t wet4 = vld1q_f32(&OutBuffer[0][OutPos+pos]);
+ wet4 = vaddq_f32(wet4, vmulq_f32(val4, gain));
+ vst1q_f32(&OutBuffer[0][OutPos+pos], wet4);
+ }
+ for(;pos < BufferSize;pos++)
+ OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
+ }
}
diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c
index 719ebd23..c4e1fdf5 100644
--- a/Alc/mixer_sse.c
+++ b/Alc/mixer_sse.c
@@ -1,6 +1,5 @@
#include "config.h"
-#ifdef HAVE_XMMINTRIN_H
#ifdef IN_IDE_PARSER
/* KDevelop's parser won't recognize these defines that get added by the -msse
* switch used to compile this source. Without them, xmmintrin.h fails to
@@ -9,7 +8,6 @@
#define __SSE__
#endif
#include <xmmintrin.h>
-#endif
#include "AL/al.h"
#include "AL/alc.h"
@@ -21,19 +19,65 @@
#include "mixer_defs.h"
-static inline void ApplyCoeffsStep(const ALuint IrSize,
+static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
+ const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
- const ALfloat (*restrict CoeffStep)[2])
+ const ALfloat (*restrict CoeffStep)[2],
+ ALfloat left, ALfloat right)
{
- __m128 coeffs, deltas;
+ const __m128 lrlr = _mm_setr_ps(left, right, left, right);
+ __m128 coeffs, deltas, imp0, imp1;
+ __m128 vals = _mm_setzero_ps();
ALuint i;
- for(i = 0;i < IrSize;i += 2)
+ if((Offset&1))
{
- coeffs = _mm_load_ps(&Coeffs[i][0]);
- deltas = _mm_load_ps(&CoeffStep[i][0]);
+ const ALuint o0 = Offset&HRIR_MASK;
+ const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK;
+
+ coeffs = _mm_load_ps(&Coeffs[0][0]);
+ deltas = _mm_load_ps(&CoeffStep[0][0]);
+ vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]);
+ imp0 = _mm_mul_ps(lrlr, coeffs);
coeffs = _mm_add_ps(coeffs, deltas);
- _mm_store_ps(&Coeffs[i][0], coeffs);
+ vals = _mm_add_ps(imp0, vals);
+ _mm_store_ps(&Coeffs[0][0], coeffs);
+ _mm_storel_pi((__m64*)&Values[o0][0], vals);
+ for(i = 1;i < IrSize-1;i += 2)
+ {
+ const ALuint o2 = (Offset+i)&HRIR_MASK;
+
+ coeffs = _mm_load_ps(&Coeffs[i+1][0]);
+ deltas = _mm_load_ps(&CoeffStep[i+1][0]);
+ vals = _mm_load_ps(&Values[o2][0]);
+ imp1 = _mm_mul_ps(lrlr, coeffs);
+ coeffs = _mm_add_ps(coeffs, deltas);
+ imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2));
+ vals = _mm_add_ps(imp0, vals);
+ _mm_store_ps(&Coeffs[i+1][0], coeffs);
+ _mm_store_ps(&Values[o2][0], vals);
+ imp0 = imp1;
+ }
+ vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]);
+ imp0 = _mm_movehl_ps(imp0, imp0);
+ vals = _mm_add_ps(imp0, vals);
+ _mm_storel_pi((__m64*)&Values[o1][0], vals);
+ }
+ else
+ {
+ for(i = 0;i < IrSize;i += 2)
+ {
+ const ALuint o = (Offset + i)&HRIR_MASK;
+
+ coeffs = _mm_load_ps(&Coeffs[i][0]);
+ deltas = _mm_load_ps(&CoeffStep[i][0]);
+ vals = _mm_load_ps(&Values[o][0]);
+ imp0 = _mm_mul_ps(lrlr, coeffs);
+ coeffs = _mm_add_ps(coeffs, deltas);
+ vals = _mm_add_ps(imp0, vals);
+ _mm_store_ps(&Coeffs[i][0], coeffs);
+ _mm_store_ps(&Values[o][0], vals);
+ }
}
}
@@ -42,7 +86,7 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
ALfloat (*restrict Coeffs)[2],
ALfloat left, ALfloat right)
{
- const __m128 lrlr = { left, right, left, right };
+ const __m128 lrlr = _mm_setr_ps(left, right, left, right);
__m128 vals = _mm_setzero_ps();
__m128 coeffs;
ALuint i;
@@ -94,28 +138,58 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
#undef SUFFIX
-void MixDirect_SSE(const DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
- ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
+void MixDirect_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
- ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
- ALfloat *restrict ClickRemoval = params->ClickRemoval;
- ALfloat *restrict PendingClicks = params->PendingClicks;
- ALfloat DrySend;
- __m128 gain;
- ALuint pos;
+ ALfloat DrySend, Step;
+ __m128 gain, step;
ALuint c;
for(c = 0;c < MaxChannels;c++)
{
- DrySend = params->Gains[srcchan][c];
+ ALuint pos = 0;
+ DrySend = Gains->Current[c];
+ Step = Gains->Step[c];
+ if(Step != 1.0f && Counter > 0)
+ {
+ /* Mix with applying gain steps in aligned multiples of 4. */
+ if(BufferSize-pos > 3 && Counter-pos > 3)
+ {
+ gain = _mm_setr_ps(
+ DrySend,
+ DrySend * Step,
+ DrySend * Step * Step,
+ DrySend * Step * Step * Step
+ );
+ step = _mm_set1_ps(Step * Step * Step * Step);
+ do {
+ const __m128 val4 = _mm_load_ps(&data[pos]);
+ __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
+ dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain));
+ gain = _mm_mul_ps(gain, step);
+ _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
+ pos += 4;
+ } while(BufferSize-pos > 3 && Counter-pos > 3);
+ DrySend = _mm_cvtss_f32(gain);
+ }
+ /* Mix with applying left over gain steps that aren't aligned multiples of 4. */
+ for(;pos < BufferSize && pos < Counter;pos++)
+ {
+ OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
+ DrySend *= Step;
+ }
+ if(pos == Counter)
+ DrySend = Gains->Target[c];
+ Gains->Current[c] = DrySend;
+ /* Mix until pos is aligned with 4 or the mix is done. */
+ for(;pos < BufferSize && (pos&3) != 0;pos++)
+ OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
+ }
+
if(!(DrySend > GAIN_SILENCE_THRESHOLD))
continue;
-
- if(OutPos == 0)
- ClickRemoval[c] -= data[0]*DrySend;
-
gain = _mm_set1_ps(DrySend);
- for(pos = 0;BufferSize-pos > 3;pos += 4)
+ for(;BufferSize-pos > 3;pos += 4)
{
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
@@ -124,41 +198,64 @@ void MixDirect_SSE(const DirectParams *params, const ALfloat *restrict data, ALu
}
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
-
- if(OutPos+pos == SamplesToDo)
- PendingClicks[c] += data[pos]*DrySend;
}
}
-void MixSend_SSE(const SendParams *params, const ALfloat *restrict data,
- ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
+void MixSend_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
+ MixGainMono *Gain, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
- ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
- ALfloat *restrict ClickRemoval = params->ClickRemoval;
- ALfloat *restrict PendingClicks = params->PendingClicks;
- ALfloat WetGain;
- __m128 gain;
- ALuint pos;
-
- WetGain = params->Gain;
- if(!(WetGain > GAIN_SILENCE_THRESHOLD))
- return;
-
- if(OutPos == 0)
- ClickRemoval[0] -= data[0] * WetGain;
-
- gain = _mm_set1_ps(WetGain);
- for(pos = 0;BufferSize-pos > 3;pos += 4)
+ ALfloat WetGain, Step;
+ __m128 gain, step;
+
{
- const __m128 val4 = _mm_load_ps(&data[pos]);
- __m128 wet4 = _mm_load_ps(&OutBuffer[0][OutPos+pos]);
- wet4 = _mm_add_ps(wet4, _mm_mul_ps(val4, gain));
- _mm_store_ps(&OutBuffer[0][OutPos+pos], wet4);
- }
- for(;pos < BufferSize;pos++)
- OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
+ ALuint pos = 0;
+ WetGain = Gain->Current;
+ Step = Gain->Step;
+ if(Step != 1.0f && Counter > 0)
+ {
+ if(BufferSize-pos > 3 && Counter-pos > 3)
+ {
+ gain = _mm_setr_ps(
+ WetGain,
+ WetGain * Step,
+ WetGain * Step * Step,
+ WetGain * Step * Step * Step
+ );
+ step = _mm_set1_ps(Step * Step * Step * Step);
+ do {
+ const __m128 val4 = _mm_load_ps(&data[pos]);
+ __m128 dry4 = _mm_load_ps(&OutBuffer[0][OutPos+pos]);
+ dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain));
+ gain = _mm_mul_ps(gain, step);
+ _mm_store_ps(&OutBuffer[0][OutPos+pos], dry4);
+ pos += 4;
+ } while(BufferSize-pos > 3 && Counter-pos > 3);
+ WetGain = _mm_cvtss_f32(gain);
+ }
+ for(;pos < BufferSize && pos < Counter;pos++)
+ {
+ OutBuffer[0][OutPos+pos] += data[pos]*WetGain;
+ WetGain *= Step;
+ }
+ if(pos == Counter)
+ WetGain = Gain->Target;
+ Gain->Current = WetGain;
+ for(;pos < BufferSize && (pos&3) != 0;pos++)
+ OutBuffer[0][OutPos+pos] += data[pos]*WetGain;
+ }
- if(OutPos+pos == SamplesToDo)
- PendingClicks[0] += data[pos] * WetGain;
+ if(!(WetGain > GAIN_SILENCE_THRESHOLD))
+ return;
+ gain = _mm_set1_ps(WetGain);
+ for(;BufferSize-pos > 3;pos += 4)
+ {
+ const __m128 val4 = _mm_load_ps(&data[pos]);
+ __m128 wet4 = _mm_load_ps(&OutBuffer[0][OutPos+pos]);
+ wet4 = _mm_add_ps(wet4, _mm_mul_ps(val4, gain));
+ _mm_store_ps(&OutBuffer[0][OutPos+pos], wet4);
+ }
+ for(;pos < BufferSize;pos++)
+ OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
+ }
}
diff --git a/Alc/mixer_sse2.c b/Alc/mixer_sse2.c
new file mode 100644
index 00000000..7670add3
--- /dev/null
+++ b/Alc/mixer_sse2.c
@@ -0,0 +1,78 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2014 by Timothy Arceri <[email protected]>.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+
+#include "alu.h"
+#include "mixer_defs.h"
+
+
+const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples)
+{
+ const __m128i increment4 = _mm_set1_epi32(increment*4);
+ const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
+ const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
+ alignas(16) union { ALuint i[4]; float f[4]; } pos_;
+ alignas(16) union { ALuint i[4]; float f[4]; } frac_;
+ __m128i frac4, pos4;
+ ALuint pos;
+ ALuint i;
+
+ InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
+
+ frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
+ pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
+
+ for(i = 0;numsamples-i > 3;i += 4)
+ {
+ const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]);
+ const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]);
+
+ /* val1 + (val2-val1)*mu */
+ const __m128 r0 = _mm_sub_ps(val2, val1);
+ const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4);
+ const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0));
+
+ _mm_store_ps(&dst[i], out);
+
+ frac4 = _mm_add_epi32(frac4, increment4);
+ pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
+ frac4 = _mm_and_si128(frac4, fracMask4);
+
+ _mm_store_ps(pos_.f, _mm_castsi128_ps(pos4));
+ }
+
+ pos = pos_.i[0];
+ frac = _mm_cvtsi128_si32(frac4);
+
+ for(;i < numsamples;i++)
+ {
+ dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
+
+ frac += increment;
+ pos += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ }
+ return dst;
+}
diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c
new file mode 100644
index 00000000..8ce8cd90
--- /dev/null
+++ b/Alc/mixer_sse41.c
@@ -0,0 +1,82 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2014 by Timothy Arceri <[email protected]>.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+
+#include "alu.h"
+#include "mixer_defs.h"
+
+
+const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples)
+{
+ const __m128i increment4 = _mm_set1_epi32(increment*4);
+ const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
+ const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
+ alignas(16) union { ALuint i[4]; float f[4]; } pos_;
+ alignas(16) union { ALuint i[4]; float f[4]; } frac_;
+ __m128i frac4, pos4;
+ ALuint pos;
+ ALuint i;
+
+ InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
+
+ frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
+ pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
+
+ for(i = 0;numsamples-i > 3;i += 4)
+ {
+ const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]);
+ const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]);
+
+ /* val1 + (val2-val1)*mu */
+ const __m128 r0 = _mm_sub_ps(val2, val1);
+ const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4);
+ const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0));
+
+ _mm_store_ps(&dst[i], out);
+
+ frac4 = _mm_add_epi32(frac4, increment4);
+ pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
+ frac4 = _mm_and_si128(frac4, fracMask4);
+
+ pos_.i[0] = _mm_extract_epi32(pos4, 0);
+ pos_.i[1] = _mm_extract_epi32(pos4, 1);
+ pos_.i[2] = _mm_extract_epi32(pos4, 2);
+ pos_.i[3] = _mm_extract_epi32(pos4, 3);
+ }
+
+ pos = pos_.i[0];
+ frac = _mm_cvtsi128_si32(frac4);
+
+ for(;i < numsamples;i++)
+ {
+ dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
+
+ frac += increment;
+ pos += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ }
+ return dst;
+}
diff --git a/Alc/rwlock.h b/Alc/rwlock.h
deleted file mode 100644
index efbab4e8..00000000
--- a/Alc/rwlock.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef AL_RWLOCK_H
-#define AL_RWLOCK_H
-
-#include "AL/al.h"
-#include "atomic.h"
-
-typedef struct {
- volatile RefCount read_count;
- volatile RefCount write_count;
- volatile ALenum read_lock;
- volatile ALenum read_entry_lock;
- volatile ALenum write_lock;
-} RWLock;
-
-void RWLockInit(RWLock *lock);
-void ReadLock(RWLock *lock);
-void ReadUnlock(RWLock *lock);
-void WriteLock(RWLock *lock);
-void WriteUnlock(RWLock *lock);
-
-#endif /* AL_RWLOCK_H */
diff --git a/Alc/threads.c b/Alc/threads.c
deleted file mode 100644
index 64586ae9..00000000
--- a/Alc/threads.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * OpenAL cross platform audio library
- * Copyright (C) 1999-2007 by authors.
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * Or go to http://www.gnu.org/copyleft/lgpl.html
- */
-
-#include "config.h"
-
-#include "threads.h"
-
-#include <stdlib.h>
-#include <errno.h>
-
-#include "alMain.h"
-#include "alThunk.h"
-
-#define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */
-
-#ifdef _WIN32
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-typedef struct althread_info {
- ALuint (*func)(ALvoid*);
- ALvoid *ptr;
- HANDLE hdl;
-} althread_info;
-
-static DWORD CALLBACK StarterFunc(void *ptr)
-{
- althread_info *inf = (althread_info*)ptr;
- ALuint ret;
-
- ret = inf->func(inf->ptr);
- ExitThread((DWORD)ret);
-
- return (DWORD)ret;
-}
-
-
-ALboolean StartThread(althread_t *thread, ALuint (*func)(ALvoid*), ALvoid *ptr)
-{
- althread_info *info;
- DWORD dummy;
-
- info = malloc(sizeof(*info));
- if(!info) return AL_FALSE;
-
- info->func = func;
- info->ptr = ptr;
-
- info->hdl = CreateThread(NULL, THREAD_STACK_SIZE, StarterFunc, info, 0, &dummy);
- if(!info->hdl)
- {
- free(info);
- return AL_FALSE;
- }
-
- *thread = info;
- return AL_TRUE;
-}
-
-ALuint StopThread(althread_t thread)
-{
- DWORD ret = 0;
-
- WaitForSingleObject(thread->hdl, INFINITE);
- GetExitCodeThread(thread->hdl, &ret);
- CloseHandle(thread->hdl);
-
- free(thread);
-
- return (ALuint)ret;
-}
-
-
-void SetThreadName(const char *name)
-{
-#if defined(_MSC_VER)
-#define MS_VC_EXCEPTION 0x406D1388
- struct {
- DWORD dwType; // Must be 0x1000.
- LPCSTR szName; // Pointer to name (in user addr space).
- DWORD dwThreadID; // Thread ID (-1=caller thread).
- DWORD dwFlags; // Reserved for future use, must be zero.
- } info;
- info.dwType = 0x1000;
- info.szName = name;
- info.dwThreadID = -1;
- info.dwFlags = 0;
-
- __try {
- RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info);
- }
- __except(EXCEPTION_CONTINUE_EXECUTION) {
- }
-#undef MS_VC_EXCEPTION
-#else
- TRACE("Can't set thread %04lx name to \"%s\"\n", GetCurrentThreadId(), name);
-#endif
-}
-
-#else
-
-#include <pthread.h>
-
-typedef struct althread_info {
- ALuint (*func)(ALvoid*);
- ALvoid *ptr;
- ALuint ret;
- pthread_t hdl;
-} althread_info;
-
-static void *StarterFunc(void *ptr)
-{
- althread_info *inf = (althread_info*)ptr;
- inf->ret = inf->func(inf->ptr);
- return NULL;
-}
-
-
-ALboolean StartThread(althread_t *thread, ALuint (*func)(ALvoid*), ALvoid *ptr)
-{
- pthread_attr_t attr;
- althread_info *info;
-
- info = malloc(sizeof(*info));
- if(!info) return AL_FALSE;
-
- if(pthread_attr_init(&attr) != 0)
- {
- free(info);
- return AL_FALSE;
- }
- if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE) != 0)
- {
- pthread_attr_destroy(&attr);
- free(info);
- return AL_FALSE;
- }
-
- info->func = func;
- info->ptr = ptr;
- if(pthread_create(&info->hdl, &attr, StarterFunc, info) != 0)
- {
- pthread_attr_destroy(&attr);
- free(info);
- return AL_FALSE;
- }
- pthread_attr_destroy(&attr);
-
- *thread = info;
- return AL_TRUE;
-}
-
-ALuint StopThread(althread_t thread)
-{
- ALuint ret;
-
- pthread_join(thread->hdl, NULL);
- ret = thread->ret;
-
- free(thread);
-
- return ret;
-}
-
-
-void SetThreadName(const char *name)
-{
-#if defined(HAVE_PTHREAD_SETNAME_NP)
-#if defined(__GNUC__)
- if(pthread_setname_np(pthread_self(), name) != 0)
-#elif defined(__APPLE__)
- if(pthread_setname_np(name) != 0)
-#endif
- WARN("Failed to set thread name to \"%s\": %s\n", name, strerror(errno));
-#elif defined(HAVE_PTHREAD_SET_NAME_NP)
- pthread_set_name_np(pthread_self(), name);
-#else
- TRACE("Can't set thread name to \"%s\"\n", name);
-#endif
-}
-
-#endif
diff --git a/Alc/uintmap.h b/Alc/uintmap.h
deleted file mode 100644
index 2c70f161..00000000
--- a/Alc/uintmap.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef AL_UINTMAP_H
-#define AL_UINTMAP_H
-
-#include "AL/al.h"
-#include "rwlock.h"
-
-typedef struct UIntMap {
- struct {
- ALuint key;
- ALvoid *value;
- } *array;
- ALsizei size;
- ALsizei maxsize;
- ALsizei limit;
- RWLock lock;
-} UIntMap;
-extern UIntMap TlsDestructor;
-
-void InitUIntMap(UIntMap *map, ALsizei limit);
-void ResetUIntMap(UIntMap *map);
-ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value);
-ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key);
-ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key);
-
-inline void LockUIntMapRead(UIntMap *map)
-{ ReadLock(&map->lock); }
-inline void UnlockUIntMapRead(UIntMap *map)
-{ ReadUnlock(&map->lock); }
-inline void LockUIntMapWrite(UIntMap *map)
-{ WriteLock(&map->lock); }
-inline void UnlockUIntMapWrite(UIntMap *map)
-{ WriteUnlock(&map->lock); }
-
-#endif /* AL_UINTMAP_H */
diff --git a/Alc/vector.h b/Alc/vector.h
new file mode 100644
index 00000000..5c094bee
--- /dev/null
+++ b/Alc/vector.h
@@ -0,0 +1,69 @@
+#ifndef AL_VECTOR_H
+#define AL_VECTOR_H
+
+#include <stdlib.h>
+
+#include <AL/al.h>
+
+/* "Base" vector type, designed to alias with the actual vector types. */
+typedef struct vector__s {
+ ALsizei Capacity;
+ ALsizei Size;
+} *vector_;
+
+#define DECL_VECTOR(T) typedef struct vector_##T##_s { \
+ ALsizei Capacity; \
+ ALsizei Size; \
+ T Data[]; \
+} *vector_##T; \
+typedef const struct vector_##T##_s *const_vector_##T;
+
+#define VECTOR_INIT(_x) do { (_x) = NULL; } while(0)
+#define VECTOR_DEINIT(_x) do { free((_x)); (_x) = NULL; } while(0)
+
+/* Helper to increase a vector's reserve. Do not call directly. */
+ALboolean vector_reserve(void *ptr, size_t base_size, size_t obj_count, size_t obj_size, ALboolean exact);
+#define VECTOR_RESERVE(_x, _c) (vector_reserve(&(_x), sizeof(*(_x)), (_c), sizeof((_x)->Data[0]), AL_TRUE))
+
+/* Helper to change a vector's size. Do not call directly. */
+ALboolean vector_resize(void *ptr, size_t base_size, size_t obj_count, size_t obj_size);
+#define VECTOR_RESIZE(_x, _c) (vector_resize(&(_x), sizeof(*(_x)), (_c), sizeof((_x)->Data[0])))
+
+#define VECTOR_CAPACITY(_x) ((const ALsizei)((_x) ? (_x)->Capacity : 0))
+#define VECTOR_SIZE(_x) ((const ALsizei)((_x) ? (_x)->Size : 0))
+
+#define VECTOR_ITER_BEGIN(_x) ((_x)->Data + 0)
+#define VECTOR_ITER_END(_x) ((_x)->Data + VECTOR_SIZE(_x))
+
+ALboolean vector_insert(void *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend);
+#ifdef __GNUC__
+#define TYPE_CHECK(T1, T2) __builtin_types_compatible_p(T1, T2)
+#define VECTOR_INSERT(_x, _i, _s, _e) __extension__({ \
+ ALboolean _r; \
+ static_assert(TYPE_CHECK(__typeof((_x)->Data[0]), __typeof(*(_i))), "Incompatible insertion iterator"); \
+ static_assert(TYPE_CHECK(__typeof((_x)->Data[0]), __typeof(*(_s))), "Incompatible insertion source type"); \
+ static_assert(TYPE_CHECK(__typeof(*(_s)), __typeof(*(_e))), "Incompatible iterator sources"); \
+ _r = vector_insert(&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_i), (_s), (_e)); \
+ _r; \
+})
+#else
+#define VECTOR_INSERT(_x, _i, _s, _e) (vector_insert(&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_i), (_s), (_e)))
+#endif
+
+#define VECTOR_PUSH_BACK(_x, _obj) (vector_reserve(&(_x), sizeof(*(_x)), VECTOR_SIZE(_x)+1, sizeof((_x)->Data[0]), AL_FALSE) && \
+ (((_x)->Data[(_x)->Size++] = (_obj)),AL_TRUE))
+#define VECTOR_POP_BACK(_x) ((void)((_x)->Size--))
+
+#define VECTOR_BACK(_x) ((_x)->Data[(_x)->Size-1])
+#define VECTOR_FRONT(_x) ((_x)->Data[0])
+
+#define VECTOR_ELEM(_x, _o) ((_x)->Data[(_o)])
+
+#define VECTOR_FOR_EACH(_t, _x, _f) do { \
+ _t *_iter = VECTOR_ITER_BEGIN((_x)); \
+ _t *_end = VECTOR_ITER_END((_x)); \
+ for(;_iter != _end;++_iter) \
+ (_f)(_iter); \
+} while(0)
+
+#endif /* AL_VECTOR_H */