diff options
Diffstat (limited to 'Alc')
56 files changed, 3940 insertions, 4344 deletions
@@ -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(); @@ -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, ¶m); @@ -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 @@ -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 */ |